LCOV - code coverage report
Current view: top level - synthesis/MeasurementComponents - SDGrid.cc (source / functions) Hit Total Coverage
Test: casa_coverage.info Lines: 892 1355 65.8 %
Date: 2023-10-25 08:47:59 Functions: 71 95 74.7 %

          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: aips2-request@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/VisBuffer.h>
      75             : #include <msvis/MSVis/VisibilityIterator.h>
      76             : #include <casacore/scimath/Mathematics/RigidVector.h>
      77             : #include <synthesis/MeasurementComponents/SDGrid.h>
      78             : #include <synthesis/TransformMachines/SkyJones.h>
      79             : #include <synthesis/TransformMachines/StokesImageUtil.h>
      80             : 
      81             : #if defined(SDGRID_PERFS)
      82             : #include <iomanip>
      83             : #include <exception>
      84             : #include <sstream>
      85             : #endif
      86             : 
      87             : using namespace casacore;
      88             : namespace casa {
      89             : 
      90             : #if defined(SDGRID_PERFS)
      91             : namespace sdgrid_perfs {
      92        1612 : ChronoStat::ChronoStat(const string & name)
      93             :     : name_ {name},
      94             :       started_ {false},
      95             :       n_laps_ {0},
      96             :       n_overflows_ {0},
      97             :       n_underflows_ {0},
      98        1612 :       laps_sum_ {Duration::zero()},
      99        1612 :       laps_min_ {Duration::max()},
     100        3224 :       laps_max_ {Duration::min()}
     101        1612 :   {}
     102             : 
     103        1612 : const std::string& ChronoStat::name() const {
     104        1612 :   return name_;
     105             : }
     106             : 
     107        1612 : void ChronoStat::setName(const std::string& name) {
     108        1612 :   name_ = name;
     109        1612 : }
     110             : 
     111      571954 : void ChronoStat::start() {
     112      571954 :   if (not started_) {
     113      571954 :     started_ = true;
     114      571954 :     ++n_laps_;
     115      571954 :     lap_start_time_ = Clock::now();
     116             :   } else {
     117           0 :     ++n_overflows_;
     118             :   }
     119      571954 : }
     120      571954 : void ChronoStat::stop() {
     121      571954 :   if (started_) {
     122      571954 :     auto lap_duration = Clock::now() - lap_start_time_;
     123      571954 :     laps_sum_ += lap_duration;
     124      571954 :     started_ = false;
     125      571954 :     if (lap_duration < laps_min_) laps_min_ = lap_duration;
     126      571954 :     if (lap_duration > laps_max_) laps_max_ = lap_duration;
     127             :   } else {
     128           0 :     ++n_underflows_;
     129             :   }
     130      571954 : }
     131             : 
     132        1612 : ChronoStat::Duration ChronoStat::lapsSum() const {
     133        1612 :   return laps_sum_;
     134             : }
     135             : 
     136        1612 : ChronoStat::Duration ChronoStat::lapsMin() const {
     137        1612 :   return n_laps_ > 0 ? laps_min_ : Duration::zero();
     138             : }
     139             : 
     140        1612 : ChronoStat::Duration ChronoStat::lapsMax() const {
     141        1612 :   return  n_laps_ > 0 ? laps_max_ : Duration::zero();
     142             : }
     143             : 
     144        1612 : ChronoStat::Duration ChronoStat::lapsMean() const {
     145        1612 :   return n_laps_ > 0 ? laps_sum_ / n_laps_ : Duration::zero();
     146             : }
     147             : 
     148        1612 : unsigned int ChronoStat::lapsCount() const {
     149        1612 :   return n_laps_;
     150             : }
     151             : 
     152           0 : bool ChronoStat::isEmpty() const {
     153           0 :   return n_laps_ == 0;
     154             : }
     155             : 
     156        1612 : unsigned int ChronoStat::nOverflows() const {
     157        1612 :   return n_overflows_;
     158             : }
     159             : 
     160        1612 : unsigned int ChronoStat::nUnderflows() const {
     161        1612 :   return n_underflows_;
     162             : }
     163             : 
     164       12896 : std::string ChronoStat::quote(const std::string& s) const {
     165       12896 :   return "\"" + s + "\"";
     166             : }
     167             : 
     168        1612 : std::string ChronoStat::json() const {
     169        3224 :   std::ostringstream os;
     170        1612 :   os << quote(name()) << ": {"
     171        3224 :          << quote("sum") << ": " << lapsSum().count()
     172        3224 :          << " ," <<  quote("count") << ": " << lapsCount()
     173        3224 :          << " ," <<  quote("min") << ": " << lapsMin().count()
     174        3224 :          << " ," <<  quote("mean") << ": " << lapsMean().count()
     175        3224 :          << " ," <<  quote("max") << ": " << lapsMax().count()
     176        3224 :          << " ," <<  quote("overflows") << ": " << nOverflows()
     177        3224 :          << " ," <<  quote("underflows") << ": " << nUnderflows()
     178        1612 :          << "}";
     179        3224 :   return os.str();
     180             : }
     181             : 
     182           0 : std::ostream& operator<<(std::ostream &os, const ChronoStat &c) {
     183           0 :   constexpr auto eol = '\n';
     184           0 :   os  << "name: " << c.name() << eol
     185           0 :     << "sum:        " << std::setw(20) << std::right << c.lapsSum().count() << eol
     186           0 :     << "count:      " << std::setw(20) << std::right << c.lapsCount() << eol
     187           0 :     << "min:        " << std::setw(20) << std::right << c.lapsMin().count() << eol
     188           0 :     << "mean:       " << std::setw(20) << std::right << c.lapsMean().count() << eol
     189           0 :     << "max:        " << std::setw(20) << std::right << c.lapsMax().count() << eol
     190           0 :     << "overflows:  " << std::setw(20) << std::right << c.nOverflows() << eol
     191           0 :     << "underflows: " << std::setw(20) << std::right << c.nUnderflows();
     192           0 :   return os;
     193             : }
     194             : 
     195      561954 : StartStop::StartStop(ChronoStat &c)
     196      561954 :   : c_ {c} {
     197      561954 :     c_.start();
     198      561954 : }
     199             : 
     200     1123908 : StartStop::~StartStop() {
     201      561954 :   c_.stop();
     202      561954 : }
     203             : 
     204             : } // namespace sdgrid_perfs
     205             : 
     206             : using namespace sdgrid_perfs;
     207             : 
     208             : #endif
     209             : 
     210          10 : SDGrid::SDGrid(SkyJones& sj, Int icachesize, Int itilesize,
     211          10 :                String iconvType, Int userSupport, Bool useImagingWeight)
     212             :   : FTMachine(), sj_p(&sj), imageCache(0), wImageCache(0),
     213             :     cachesize(icachesize), tilesize(itilesize),
     214             :     isTiled(false), wImage(0), arrayLattice(0),  wArrayLattice(0), lattice(0), wLattice(0), convType(iconvType),
     215          10 :     pointingToImage(0), rowPixel {xyPos, false}, userSetSupport_p(userSupport),
     216             :     truncate_p(-1.0), gwidth_p(0.0), jwidth_p(0.0),
     217             :     minWeight_p(0.), lastIndexPerAnt_p(), useImagingWeight_p(useImagingWeight), lastAntID_p(-1), msId_p(-1),
     218             :     isSplineInterpolationReady(false), interpolator(0), clipminmax_(false),
     219             :     cache {Cache(*(const_cast<SDGrid *>(this)))},
     220          10 :     cacheIsEnabled {false}
     221             : {
     222          10 :   lastIndex_p=0;
     223          10 :   initPerfs();
     224          10 : }
     225             : 
     226          18 : SDGrid::SDGrid(MPosition& mLocation, SkyJones& sj, Int icachesize, Int itilesize,
     227          18 :                String iconvType, Int userSupport, Float minweight, Bool clipminmax, Bool useImagingWeight)
     228             :   : FTMachine(),  sj_p(&sj), imageCache(0), wImageCache(0),
     229             :     cachesize(icachesize), tilesize(itilesize),
     230             :     isTiled(false), wImage(0), arrayLattice(0),  wArrayLattice(0), lattice(0), wLattice(0), convType(iconvType),
     231          18 :     pointingToImage(0), rowPixel {xyPos, false}, userSetSupport_p(userSupport),
     232             :     truncate_p(-1.0), gwidth_p(0.0),  jwidth_p(0.0),
     233             :     minWeight_p(minweight), lastIndexPerAnt_p(), useImagingWeight_p(useImagingWeight), lastAntID_p(-1), msId_p(-1),
     234             :     isSplineInterpolationReady(false), interpolator(0), clipminmax_(clipminmax),
     235             :     cache {Cache(*(const_cast<SDGrid *>(this)))},
     236          18 :     cacheIsEnabled {false}
     237             : {
     238          18 :   mLocation_p=mLocation;
     239          18 :   lastIndex_p=0;
     240          18 :   initPerfs();
     241          18 : }
     242             : 
     243           0 : SDGrid::SDGrid(Int icachesize, Int itilesize,
     244           0 :                String iconvType, Int userSupport, Bool useImagingWeight)
     245             :   : FTMachine(), sj_p(0), imageCache(0), wImageCache(0),
     246             :     cachesize(icachesize), tilesize(itilesize),
     247             :     isTiled(false), wImage(0), arrayLattice(0),  wArrayLattice(0), lattice(0), wLattice(0), convType(iconvType),
     248           0 :     pointingToImage(0), rowPixel {xyPos, false}, userSetSupport_p(userSupport),
     249             :     truncate_p(-1.0), gwidth_p(0.0), jwidth_p(0.0),
     250             :     minWeight_p(0.), lastIndexPerAnt_p(), useImagingWeight_p(useImagingWeight), lastAntID_p(-1), msId_p(-1),
     251             :     isSplineInterpolationReady(false), interpolator(0), clipminmax_(false),
     252             :     cache {Cache(*(const_cast<SDGrid *>(this)))},
     253           0 :     cacheIsEnabled {false}
     254             : {
     255           0 :   lastIndex_p=0;
     256           0 :   initPerfs();
     257           0 : }
     258             : 
     259          93 : SDGrid::SDGrid(MPosition &mLocation, Int icachesize, Int itilesize,
     260          93 :                String iconvType, Int userSupport, Float minweight, Bool clipminmax, Bool useImagingWeight)
     261             :   : FTMachine(), sj_p(0), imageCache(0), wImageCache(0),
     262             :     cachesize(icachesize), tilesize(itilesize),
     263             :     isTiled(false), wImage(0), arrayLattice(0),  wArrayLattice(0), lattice(0), wLattice(0), convType(iconvType),
     264          93 :     pointingToImage(0), rowPixel {xyPos, false}, userSetSupport_p(userSupport),
     265             :     truncate_p(-1.0), gwidth_p(0.0), jwidth_p(0.0),
     266             :     minWeight_p(minweight), lastIndexPerAnt_p(), useImagingWeight_p(useImagingWeight), lastAntID_p(-1),
     267             :     msId_p(-1),
     268             :     isSplineInterpolationReady(false), interpolator(0), clipminmax_(clipminmax),
     269             :     cache {Cache(*(const_cast<SDGrid *>(this)))},
     270          93 :     cacheIsEnabled {false}
     271             : {
     272          93 :   mLocation_p=mLocation;
     273          93 :   lastIndex_p=0;
     274          93 :   initPerfs();
     275          93 : }
     276             : 
     277           3 : SDGrid::SDGrid(MPosition &mLocation, Int icachesize, Int itilesize,
     278             :                String iconvType, Float truncate, Float gwidth, Float jwidth,
     279           3 :                Float minweight, Bool clipminmax, Bool useImagingWeight)
     280             :   : FTMachine(), sj_p(0), imageCache(0), wImageCache(0),
     281             :     cachesize(icachesize), tilesize(itilesize),
     282             :     isTiled(false), wImage(0), arrayLattice(0),  wArrayLattice(0), lattice(0), wLattice(0), convType(iconvType),
     283           3 :     pointingToImage(0), rowPixel {xyPos, false}, userSetSupport_p(-1),
     284             :     truncate_p(truncate), gwidth_p(gwidth), jwidth_p(jwidth),
     285             :     minWeight_p(minweight), lastIndexPerAnt_p(), useImagingWeight_p(useImagingWeight), lastAntID_p(-1), msId_p(-1),
     286             :     isSplineInterpolationReady(false), interpolator(0), clipminmax_(clipminmax),
     287             :     cache {Cache(*(const_cast<SDGrid *>(this)))},
     288           3 :     cacheIsEnabled {false}
     289             : {
     290           3 :   mLocation_p=mLocation;
     291           3 :   lastIndex_p=0;
     292           3 :   initPerfs();
     293           3 : }
     294             : 
     295             : //----------------------------------------------------------------------
     296             : 
     297         124 : void SDGrid::initPerfs() {
     298             : #if defined(SDGRID_PERFS)
     299         124 :   cNextChunk.setName("iterateNextChunk");
     300         124 :   cMatchAllSpwChans.setName("matchAllSpwChans");
     301         124 :   cMatchChannel.setName("matchChannel");
     302         124 :   cPickWeights.setName("pickWeights");
     303         124 :   cInterpolateFrequencyToGrid.setName("interpolateFrequencyToGrid");
     304         124 :   cSearchValidPointing.setName("searchValidPointing");
     305         124 :   cComputeSplines.setName("computeSplines");
     306         124 :   cResetFrame.setName("resetFrame");
     307         124 :   cInterpolateDirection.setName("interpolateDirection");
     308         124 :   cConvertDirection.setName("convertDirection");
     309         124 :   cComputeDirectionPixel.setName("computeDirectionPixel");
     310         124 :   cHandleMovingSource.setName("handleMovingSource");
     311         124 :   cGridData.setName("gridData");
     312             : #endif
     313         124 : }
     314             : 
     315             : 
     316             : 
     317             : //----------------------------------------------------------------------
     318           0 : SDGrid& SDGrid::operator=(const SDGrid& other)
     319             : {
     320           0 :   if(this!=&other) {
     321             :      //Do the base parameters
     322           0 :     FTMachine::operator=(other);
     323           0 :     sj_p=other.sj_p;
     324           0 :     imageCache=other.imageCache;
     325           0 :     wImage=other.wImage;
     326           0 :     wImageCache=other.wImageCache;
     327           0 :     cachesize=other.cachesize;
     328           0 :     tilesize=other.tilesize;
     329           0 :     isTiled=other.isTiled;
     330           0 :     lattice=other.lattice;
     331           0 :     arrayLattice=other.arrayLattice;
     332           0 :     wLattice=other.wLattice;
     333           0 :     wArrayLattice=other.wArrayLattice;
     334           0 :     convType=other.convType;
     335           0 :     if(other.wImage !=0)
     336           0 :       wImage=(TempImage<Float> *)other.wImage->cloneII();
     337             :     else
     338           0 :       wImage=0;
     339           0 :     pointingDirCol_p=other.pointingDirCol_p;
     340           0 :     pointingToImage=0;
     341           0 :     xyPos.resize();
     342           0 :     xyPos=other.xyPos;
     343           0 :     rowPixel = MaskedPixelRef(xyPos, false);
     344           0 :     xyPosMovingOrig_p=other.xyPosMovingOrig_p;
     345           0 :     convFunc.resize();
     346           0 :     convFunc=other.convFunc;
     347           0 :     convSampling=other.convSampling;
     348           0 :     convSize=other.convSize;
     349           0 :     convSupport=other.convSupport;
     350           0 :     userSetSupport_p=other.userSetSupport_p;
     351           0 :     lastIndex_p=0;
     352           0 :     lastIndexPerAnt_p=0;
     353           0 :     lastAntID_p=-1;
     354           0 :     msId_p=-1;
     355           0 :     useImagingWeight_p=other.useImagingWeight_p;
     356           0 :     clipminmax_=other.clipminmax_;
     357           0 :     cacheIsEnabled=false;
     358           0 :     cache=Cache(*(const_cast<SDGrid *>(this)));
     359             :   };
     360           0 :   return *this;
     361             : };
     362             : 
     363         474 : String SDGrid::name() const{
     364         474 :     return String("SDGrid");
     365             : }
     366             : 
     367             : void
     368         114 : SDGrid::setEnableCache(Bool doEnable) {
     369         114 :     cacheIsEnabled = doEnable;
     370         114 : }
     371             : 
     372             : //----------------------------------------------------------------------
     373             : // Odds are that it changed.....
     374         338 : Bool SDGrid::changed(const VisBuffer& /*vb*/) {
     375         338 :   return false;
     376             : }
     377             : 
     378             : //----------------------------------------------------------------------
     379           0 : SDGrid::SDGrid(const SDGrid& other)
     380             :   : FTMachine(),
     381           0 :     rowPixel {MaskedPixelRef(xyPos)},
     382           0 :     cache {Cache(*const_cast<SDGrid *>(this))}
     383             : {
     384           0 :   operator=(other);
     385           0 : }
     386             : 
     387             : #define NEED_UNDERSCORES
     388             : #if defined(NEED_UNDERSCORES)
     389             : #define grdsf grdsf_
     390             : #define grdgauss grdgauss_
     391             : #define grdjinc1 grdjinc1_
     392             : #endif
     393             : 
     394             : extern "C" {
     395             :    void grdsf(Double*, Double*);
     396             :    void grdgauss(Double*, Double*, Double*);
     397             :    void grdjinc1(Double*, Double*, Int*, Double*);
     398             : }
     399             : 
     400           0 : void SDGrid::dumpConvolutionFunction(const casacore::String &outfile,
     401             :         const casacore::Vector<casacore::Float> &f) const {
     402             : 
     403           0 :     ofstream ofs(outfile.c_str());
     404           0 :     for (size_t i = 0 ; i < f.nelements() ; i++) {
     405           0 :         ofs << i << " " << f[i] << endl;
     406             :     }
     407           0 :     ofs.close();
     408           0 : }
     409             : 
     410             : //----------------------------------------------------------------------
     411         238 : void SDGrid::init() {
     412             : 
     413         238 :     logIO() << LogOrigin("SDGrid", "init")  << LogIO::NORMAL;
     414             : 
     415         238 :     ok();
     416             : 
     417         238 :     isTiled = false;
     418         238 :     nx    = image->shape()(0);
     419         238 :     ny    = image->shape()(1);
     420         238 :     npol  = image->shape()(2);
     421         238 :     nchan = image->shape()(3);
     422             : 
     423         238 :     sumWeight.resize(npol, nchan);
     424             : 
     425             :     // Set up image cache needed for gridding. For BOX-car convolution
     426             :     // we can use non-overlapped tiles. Otherwise we need to use
     427             :     // overlapped tiles and additive gridding so that only increments
     428             :     // to a tile are written.
     429         238 :     if (imageCache) delete imageCache;
     430         238 :     imageCache = nullptr;
     431             : 
     432         238 :     convType = downcase(convType);
     433         238 :     logIO() << "Convolution function : " << convType << LogIO::DEBUG1 << LogIO::POST;
     434             : 
     435             :     // Compute convolution function
     436         238 :     if (convType=="pb") {
     437             :         // Do nothing
     438             :     }
     439         192 :     else if (convType=="box") {
     440         174 :         convSupport=(userSetSupport_p >= 0) ? userSetSupport_p : 0;
     441         174 :         logIO() << "Support : " << convSupport << " pixels" << LogIO::POST;
     442         174 :         convSampling=100;
     443         174 :         convSize=convSampling*(2*convSupport+2);
     444         174 :         convFunc.resize(convSize);
     445         174 :         convFunc=0.0;
     446       17574 :         for (Int i=0;i<convSize/2;i++) {
     447       17400 :             convFunc(i)=1.0;
     448             :         }
     449             :     }
     450          18 :     else if (convType=="sf") {
     451          12 :         convSupport=(userSetSupport_p >= 0) ? userSetSupport_p : 3;
     452          12 :         logIO() << "Support : " << convSupport << " pixels" << LogIO::POST;
     453          12 :         convSampling=100;
     454          12 :         convSize=convSampling*(2*convSupport+2);
     455          12 :         convFunc.resize(convSize);
     456          12 :         convFunc=0.0;
     457        6612 :         for (Int i=0;i<convSampling*convSupport;i++) {
     458        6600 :             Double nu=Double(i)/Double(convSupport*convSampling);
     459             :             Double val;
     460        6600 :             grdsf(&nu, &val);
     461        6600 :             convFunc(i)=(1.0-nu*nu)*val;
     462             :         }
     463             :     }
     464           6 :     else if (convType=="gauss") {
     465             :         // default is b=1.0 (Mangum et al. 2007)
     466           2 :         Double hwhm=(gwidth_p > 0.0) ? Double(gwidth_p) : sqrt(log(2.0));
     467           2 :         Float truncate=(truncate_p >= 0.0) ? truncate_p : 3.0*hwhm;
     468           2 :         convSampling=100;
     469           2 :         Int itruncate=(Int)(truncate*Double(convSampling)+0.5);
     470           2 :         logIO() << LogIO::DEBUG1 << "hwhm=" << hwhm << LogIO::POST;
     471           2 :         logIO() << LogIO::DEBUG1 << "itruncate=" << itruncate << LogIO::POST;
     472             :         //convSupport=(Int)(truncate+0.5);
     473           2 :         convSupport = (Int)(truncate);
     474           2 :         convSupport += (((truncate-(Float)convSupport) > 0.0) ? 1 : 0);
     475           2 :         convSize=convSampling*(2*convSupport+2);
     476           2 :         convFunc.resize(convSize);
     477           2 :         convFunc=0.0;
     478             :         Double val, x;
     479         504 :         for (Int i = 0 ; i <= itruncate ; i++) {
     480         502 :             x = Double(i)/Double(convSampling);
     481         502 :             grdgauss(&hwhm, &x, &val);
     482         502 :             convFunc(i)=val;
     483             :         }
     484             :     }
     485           4 :     else if (convType=="gjinc") {
     486             :         // default is b=2.52, c=1.55 (Mangum et al. 2007)
     487           4 :         Double hwhm = (gwidth_p > 0.0) ? Double(gwidth_p) : sqrt(log(2.0))*2.52;
     488           4 :         Double c = (jwidth_p > 0.0) ? Double(jwidth_p) : 1.55;
     489             :         //Float truncate = truncate_p;
     490           4 :         convSampling = 100;
     491           4 :         Int itruncate=(Int)(truncate_p*Double(convSampling)+0.5);
     492           4 :         logIO() << LogIO::DEBUG1 << "hwhm=" << hwhm << LogIO::POST;
     493           4 :         logIO() << LogIO::DEBUG1 << "c=" << c << LogIO::POST;
     494           4 :         logIO() << LogIO::DEBUG1 << "itruncate=" << itruncate << LogIO::POST;
     495             :         //convSupport=(truncate_p >= 0.0) ? (Int)(truncate_p+0.5) : (Int)(2*c+0.5);
     496           4 :         Float convSupportF = (truncate_p >= 0.0) ? truncate_p : (2*c);
     497           4 :         convSupport = (Int)convSupportF;
     498           4 :         convSupport += (((convSupportF-(Float)convSupport) > 0.0) ? 1 : 0);
     499           4 :         convSize=convSampling*(2*convSupport+2);
     500           4 :         convFunc.resize(convSize);
     501           4 :         convFunc=0.0;
     502             :         //UNUSED: Double r;
     503             :         Double x, val1, val2;
     504           4 :         Int normalize = 1;
     505           4 :         if (itruncate >= 0) {
     506           0 :             for (Int i = 0 ; i < itruncate ; i++) {
     507           0 :                 x = Double(i) / Double(convSampling);
     508             :                 //r = Double(i) / (Double(hwhm)*Double(convSampling));
     509           0 :                 grdgauss(&hwhm, &x, &val1);
     510           0 :                 grdjinc1(&c, &x, &normalize, &val2);
     511           0 :                 convFunc(i) = val1 * val2;
     512             :             }
     513             :         }
     514             :         else {
     515             :             // default is to truncate at first null
     516         764 :             for (Int i=0;i<convSize;i++) {
     517         764 :                 x = Double(i) / Double(convSampling);
     518             :                 //r = Double(i) / (Double(hwhm)*Double(convSampling));
     519         764 :                 grdjinc1(&c, &x, &normalize, &val2);
     520         764 :                 if (val2 <= 0.0) {
     521             :                     logIO() << LogIO::DEBUG1
     522             :                         << "convFunc is automatically truncated at radius "
     523           4 :                         << x << LogIO::POST;
     524           4 :                     break;
     525             :                 }
     526         760 :                 grdgauss(&hwhm, &x, &val1);
     527         760 :                 convFunc(i) = val1 * val2;
     528             :             }
     529             :         }
     530             :     }
     531             :     else {
     532           0 :         logIO_p << "Unknown convolution function " << convType << LogIO::EXCEPTION;
     533             :     }
     534             : 
     535             :     // Convolution function debug
     536             :     // String outfile = convType + ".dat";
     537             :     // dumpConvolutionFunction(outfile,convFunc);
     538             : 
     539         238 :     if (wImage) delete wImage;
     540         238 :     wImage = new TempImage<Float>(image->shape(), image->coordinates());
     541             : 
     542         238 : }
     543             : 
     544         124 : void SDGrid::collectPerfs(){
     545             : #if defined(SDGRID_PERFS)
     546         372 :   LogIO os(LogOrigin(name(), "collectPerfs"));
     547             :   std::vector<std::string> probes_json {
     548             :       cNextChunk.json()
     549             :     , cMatchAllSpwChans.json()
     550             :     , cMatchChannel.json()
     551             :     , cPickWeights.json()
     552             :     , cInterpolateFrequencyToGrid.json()
     553             :     , cSearchValidPointing.json()
     554             :     , cComputeSplines.json()
     555             :     , cResetFrame.json()
     556             :     , cInterpolateDirection.json()
     557             :     , cConvertDirection.json()
     558             :     , cComputeDirectionPixel.json()
     559             :     , cHandleMovingSource.json()
     560             :     , cGridData.json()
     561        1860 :   };
     562             :   os << "PERFS<SDGRID> "
     563             :      << "{ \"note\": \"sum, min, mean, max are in units of nanoseconds.\""
     564             :      << ", \"probes\": "
     565         248 :      <<        "{ " << join(probes_json.data(), probes_json.size(), ", " ) << " }"
     566             :      << " }"
     567         248 :      << LogIO::POST;
     568             : #endif
     569         124 : }
     570             : 
     571             : 
     572             : // This is nasty, we should use CountedPointers here.
     573         248 : SDGrid::~SDGrid() {
     574             :   //fclose(pfile);
     575         124 :   if (imageCache) delete imageCache; imageCache = 0;
     576         124 :   if (arrayLattice) delete arrayLattice; arrayLattice = 0;
     577         124 :   if (wImage) delete wImage; wImage = 0;
     578         124 :   if (wImageCache) delete wImageCache; wImageCache = 0;
     579         124 :   if (wArrayLattice) delete wArrayLattice; wArrayLattice = 0;
     580         124 :   if (interpolator) delete interpolator; interpolator = 0;
     581             : 
     582         124 :   collectPerfs();
     583         248 : }
     584             : 
     585          46 : void SDGrid::findPBAsConvFunction(const ImageInterface<Complex>& image,
     586             :                                   const VisBuffer& vb) {
     587             : 
     588             :   // Get the coordinate system and increase the sampling by
     589             :   // a factor of ~ 100.
     590          92 :   CoordinateSystem coords(image.coordinates());
     591             : 
     592             :   // Set up the convolution function: make the buffer plenty
     593             :   // big so that we can trim it back
     594          46 :   convSupport=max(128, sj_p->support(vb, coords));
     595             : 
     596          46 :   convSampling=100;
     597          46 :   convSize=convSampling*convSupport;
     598             : 
     599             :   // Make a one dimensional image to calculate the
     600             :   // primary beam. We oversample this by a factor of
     601             :   // convSampling.
     602          46 :   Int directionIndex=coords.findCoordinate(Coordinate::DIRECTION);
     603          46 :   AlwaysAssert(directionIndex>=0, AipsError);
     604          92 :   DirectionCoordinate dc=coords.directionCoordinate(directionIndex);
     605          92 :   Vector<Double> sampling;
     606          46 :   sampling = dc.increment();
     607          46 :   sampling*=1.0/Double(convSampling);
     608          46 :   dc.setIncrement(sampling);
     609             : 
     610             :   // Set the reference value to the first pointing in the coordinate
     611             :   // system used in the POINTING table.
     612             :   {
     613          46 :     uInt row=0;
     614             : 
     615             :     // reset lastAntID_p to use correct antenna position
     616          46 :     lastAntID_p = -1;
     617             : 
     618          46 :     const MSPointingColumns& act_mspc = vb.msColumns().pointing();
     619          46 :     Bool nullPointingTable=(act_mspc.nrow() < 1);
     620             :     // uInt pointIndex=getIndex(*mspc, vb.time()(row), vb.timeInterval()(row), vb.antenna1()(row));
     621          46 :     Int pointIndex=-1;
     622          46 :     if(!nullPointingTable){
     623             :       //if(vb.newMS()) This thing is buggy...using msId change
     624          46 :       if(vb.msId() != msId_p){
     625          28 :         lastIndex_p=0;
     626          28 :   if(lastIndexPerAnt_p.nelements() < (size_t)vb.numberAnt()) {
     627          28 :     lastIndexPerAnt_p.resize(vb.numberAnt());
     628             :   }
     629          28 :         lastIndexPerAnt_p=0;
     630          28 :         msId_p=vb.msId();
     631             :       }
     632          46 :       pointIndex=getIndex(act_mspc, vb.time()(row), -1.0, vb.antenna1()(row));
     633          46 :       if(pointIndex < 0)
     634           0 :         pointIndex=getIndex(act_mspc, vb.time()(row), vb.timeInterval()(row), vb.antenna1()(row));
     635             : 
     636             :     }
     637          46 :     if(!nullPointingTable && ((pointIndex<0)||(pointIndex>=Int(act_mspc.time().nrow())))) {
     638           0 :       ostringstream o;
     639           0 :       o << "Failed to find pointing information for time " <<
     640           0 :         MVTime(vb.time()(row)/86400.0);
     641           0 :       logIO_p << String(o) << LogIO::EXCEPTION;
     642             :     }
     643          92 :     MEpoch epoch(Quantity(vb.time()(row), "s"));
     644          46 :     if(!pointingToImage) {
     645          46 :       lastAntID_p=vb.antenna1()(row);
     646          92 :       MPosition pos;
     647          46 :       pos=vb.msColumns().antenna().positionMeas()(lastAntID_p);
     648          46 :       mFrame_p=MeasFrame(epoch, pos);
     649          46 :       if(!nullPointingTable){
     650          46 :         worldPosMeas=directionMeas(act_mspc, pointIndex);
     651             :       }
     652             :       else{
     653           0 :         worldPosMeas=vb.direction1()(row);
     654             :       }
     655             :       // Make a machine to convert from the worldPosMeas to the output
     656             :       // Direction Measure type for the relevant frame
     657          92 :       MDirection::Ref outRef(dc.directionType(), mFrame_p);
     658          46 :       pointingToImage = new MDirection::Convert(worldPosMeas, outRef);
     659             : 
     660          46 :       if(!pointingToImage) {
     661           0 :         logIO_p << "Cannot make direction conversion machine" << LogIO::EXCEPTION;
     662             :       }
     663             :     }
     664             :     else {
     665           0 :       mFrame_p.resetEpoch(epoch);
     666           0 :       if(lastAntID_p != vb.antenna1()(row)){
     667           0 :         logIO_p << LogIO::DEBUGGING
     668             :           << "updating antenna position. MS ID " << msId_p
     669             :           << ", last antenna ID " << lastAntID_p
     670           0 :           << " new antenna ID " << vb.antenna1()(row) << LogIO::POST;
     671           0 :         MPosition pos;
     672           0 :         lastAntID_p=vb.antenna1()(row);
     673           0 :         pos=vb.msColumns().antenna().positionMeas()(lastAntID_p);
     674           0 :         mFrame_p.resetPosition(pos);
     675             :       }
     676             :     }
     677          46 :     if(!nullPointingTable){
     678          46 :       worldPosMeas=(*pointingToImage)(directionMeas(act_mspc,pointIndex));
     679             :     }
     680             :     else{
     681           0 :       worldPosMeas=(*pointingToImage)(vb.direction1()(row));
     682             :     }
     683          46 :     delete pointingToImage;
     684          46 :     pointingToImage=0;
     685             :   }
     686             : 
     687          46 :   directionCoord=coords.directionCoordinate(directionIndex);
     688             :   //make sure we use the same units
     689          46 :   worldPosMeas.set(dc.worldAxisUnits()(0));
     690             : 
     691             :   // Reference pixel may be modified in dc.setReferenceValue when
     692             :   // projection type is SFL. To take into account this effect,
     693             :   // keep original reference pixel here and subtract it from
     694             :   // the reference pixel after dc.setReferenceValue instead
     695             :   // of setting reference pixel to (0,0).
     696          92 :   Vector<Double> const originalReferencePixel = dc.referencePixel();
     697          46 :   dc.setReferenceValue(worldPosMeas.getAngle().getValue());
     698             :   //Vector<Double> unitVec(2);
     699             :   //unitVec=0.0;
     700             :   //dc.setReferencePixel(unitVec);
     701         138 :   Vector<Double> updatedReferencePixel = dc.referencePixel() - originalReferencePixel;
     702          46 :   dc.setReferencePixel(updatedReferencePixel);
     703             : 
     704          46 :   coords.replaceCoordinate(dc, directionIndex);
     705             : 
     706          92 :   IPosition pbShape(4, convSize, 2, 1, 1);
     707          92 :   IPosition start(4, 0, 0, 0, 0);
     708             : 
     709          92 :   TempImage<Complex> onedPB(pbShape, coords);
     710             : 
     711          46 :   onedPB.set(Complex(1.0, 0.0));
     712             : 
     713          46 :   AlwaysAssert(sj_p, AipsError);
     714          46 :   sj_p->apply(onedPB, onedPB, vb, 0);
     715             : 
     716          92 :   IPosition pbSlice(4, convSize, 1, 1, 1);
     717         138 :   Vector<Float> tempConvFunc=real(onedPB.getSlice(start, pbSlice, true));
     718             :   // Find number of significant points
     719          46 :   uInt cfLen=0;
     720      168404 :   for(uInt i=0;i<tempConvFunc.nelements();++i) {
     721      168404 :     if(tempConvFunc(i)<1e-3) break;
     722      168358 :     ++cfLen;
     723             :   }
     724          46 :   if(cfLen<1) {
     725             :     logIO() << LogIO::SEVERE
     726             :             << "Possible problem in primary beam calculation: no points in gridding function"
     727           0 :             << " - no points to be gridded on this image?" << LogIO::POST;
     728           0 :     cfLen=1;
     729             :   }
     730          46 :   Vector<Float> trimConvFunc=tempConvFunc(Slice(0,cfLen-1,1));
     731             : 
     732             :   // Now fill in the convolution function vector
     733          46 :   convSupport=cfLen/convSampling;
     734          46 :   convSize=convSampling*(2*convSupport+2);
     735          46 :   convFunc.resize(convSize);
     736          46 :   convFunc=0.0;
     737          46 :   convFunc(Slice(0,cfLen-1,1))=trimConvFunc(Slice(0,cfLen-1,1));
     738             : 
     739             : 
     740          46 : }
     741             : 
     742             : // Initialize for a transform from the Sky domain. This means that
     743             : // we grid-correct, and FFT the image
     744          10 : void SDGrid::initializeToVis(ImageInterface<Complex>& iimage,
     745             :                              const VisBuffer& vb)
     746             : {
     747          10 :   image=&iimage;
     748             : 
     749          10 :   ok();
     750             : 
     751          10 :   init();
     752             : 
     753          10 :   if(convType=="pb") {
     754          10 :     findPBAsConvFunction(*image, vb);
     755             :   }
     756             : 
     757             :   // reset msId_p and lastAntID_p to -1
     758             :   // this is to ensure correct antenna position in getXYPos
     759          10 :   msId_p = -1;
     760          10 :   lastAntID_p = -1;
     761             : 
     762             :   // Initialize the maps for polarization and channel. These maps
     763             :   // translate visibility indices into image indices
     764          10 :   initMaps(vb);
     765             : 
     766             :   // First get the CoordinateSystem for the image and then find
     767             :   // the DirectionCoordinate
     768          20 :   CoordinateSystem coords=image->coordinates();
     769          10 :   Int directionIndex=coords.findCoordinate(Coordinate::DIRECTION);
     770          10 :   AlwaysAssert(directionIndex>=0, AipsError);
     771          10 :   directionCoord=coords.directionCoordinate(directionIndex);
     772             :   /*if((image->shape().product())>cachesize) {
     773             :     isTiled=true;
     774             :   }
     775             :   else {
     776             :     isTiled=false;
     777             :     }*/
     778          10 :   isTiled=false;
     779          10 :   nx    = image->shape()(0);
     780          10 :   ny    = image->shape()(1);
     781          10 :   npol  = image->shape()(2);
     782          10 :   nchan = image->shape()(3);
     783             : 
     784             :   // If we are memory-based then read the image in and create an
     785             :   // ArrayLattice otherwise just use the PagedImage
     786             :   /*if(isTiled) {
     787             :     lattice=image;
     788             :     wLattice=wImage;
     789             :   }
     790             :   else*/
     791             : {
     792             :     // Make the grid the correct shape and turn it into an array lattice
     793          20 :     IPosition gridShape(4, nx, ny, npol, nchan);
     794          10 :     griddedData.resize(gridShape);
     795          10 :     griddedData = Complex(0.0);
     796             : 
     797          10 :     wGriddedData.resize(gridShape);
     798          10 :     wGriddedData = 0.0;
     799             : 
     800          10 :     if(arrayLattice) delete arrayLattice; arrayLattice=0;
     801          10 :     arrayLattice = new ArrayLattice<Complex>(griddedData);
     802             : 
     803          10 :     if(wArrayLattice) delete wArrayLattice; wArrayLattice=0;
     804          10 :     wArrayLattice = new ArrayLattice<Float>(wGriddedData);
     805          10 :     wArrayLattice->set(0.0);
     806          10 :     wLattice=wArrayLattice;
     807             : 
     808             :     // Now find the SubLattice corresponding to the image
     809          30 :     IPosition blc(4, (nx-image->shape()(0)+(nx%2==0))/2, (ny-image->shape()(1)+(ny%2==0))/2, 0, 0);
     810          20 :     IPosition stride(4, 1);
     811          30 :     IPosition trc(blc+image->shape()-stride);
     812          20 :     LCBox gridBox(blc, trc, gridShape);
     813          20 :     SubLattice<Complex> gridSub(*arrayLattice, gridBox, true);
     814             : 
     815             :     // Do the copy
     816          10 :     gridSub.copyData(*image);
     817             : 
     818          10 :     lattice=arrayLattice;
     819             :   }
     820             : 
     821          10 :   AlwaysAssert(lattice, AipsError);
     822          10 :   AlwaysAssert(wLattice, AipsError);
     823             : 
     824          10 : }
     825             : 
     826           0 : void SDGrid::finalizeToVis()
     827             : {
     828             :   /*if(isTiled) {
     829             : 
     830             :     logIO() << LogOrigin("SDGrid", "finalizeToVis")  << LogIO::NORMAL;
     831             : 
     832             :     AlwaysAssert(imageCache, AipsError);
     833             :     AlwaysAssert(image, AipsError);
     834             :     ostringstream o;
     835             :     imageCache->flush();
     836             :     imageCache->showCacheStatistics(o);
     837             :     logIO() << o.str() << LogIO::POST;
     838             :     }*/
     839           0 :   if(pointingToImage) delete pointingToImage; pointingToImage=0;
     840           0 : }
     841             : 
     842             : 
     843             : // Initialize the FFT to the Sky.
     844             : // Here we have to setup and initialize the grid.
     845         228 : void SDGrid::initializeToSky(ImageInterface<Complex>& iimage,
     846             :         Matrix<Float>& weight, const VisBuffer& vb)
     847             : {
     848             :     // image always points to the image
     849         228 :     image=&iimage;
     850             : 
     851         228 :     ok();
     852             : 
     853         228 :     init();
     854             : 
     855         228 :     if (convType == "pb") findPBAsConvFunction(*image, vb);
     856             : 
     857             :     // reset msId_p and lastAntID_p to -1
     858             :     // this is to ensure correct antenna position in getXYPos
     859         228 :     msId_p = -1;
     860         228 :     lastAntID_p = -1;
     861             : 
     862             :     // Initialize the maps for polarization and channel.
     863             :     // These maps translate visibility indices into image indices
     864         228 :     initMaps(vb);
     865             : 
     866             :     // No longer using isTiled
     867         228 :     isTiled=false;
     868         228 :     nx    = image->shape()(0);
     869         228 :     ny    = image->shape()(1);
     870         228 :     npol  = image->shape()(2);
     871         228 :     nchan = image->shape()(3);
     872             : 
     873         228 :     sumWeight = 0.0;
     874         228 :     weight.resize(sumWeight.shape());
     875         228 :     weight = 0.0;
     876             : 
     877             :     // First get the CoordinateSystem for the image
     878             :     // and then find the DirectionCoordinate
     879         456 :     CoordinateSystem coords = image->coordinates();
     880         228 :     Int directionIndex = coords.findCoordinate(Coordinate::DIRECTION);
     881         228 :     AlwaysAssert(directionIndex >= 0, AipsError);
     882         228 :     directionCoord = coords.directionCoordinate(directionIndex);
     883             : 
     884             :     // Initialize for in memory gridding.
     885             :     // lattice will point to the ArrayLattice
     886         456 :     IPosition gridShape(4, nx, ny, npol, nchan);
     887         456 :     logIO() << LogOrigin("SDGrid", "initializeToSky", WHERE) << LogIO::DEBUGGING
     888         456 :         << "gridShape = " << gridShape << LogIO::POST;
     889             : 
     890         228 :     griddedData.resize(gridShape);
     891         228 :     griddedData = Complex(0.0);
     892         228 :     if (arrayLattice) delete arrayLattice;
     893         228 :     arrayLattice = new ArrayLattice<Complex>(griddedData);
     894         228 :     lattice = arrayLattice;
     895         228 :     AlwaysAssert(lattice, AipsError);
     896             : 
     897         228 :     wGriddedData.resize(gridShape);
     898         228 :     wGriddedData=0.0;
     899         228 :     if (wArrayLattice) delete wArrayLattice;
     900         228 :     wArrayLattice = new ArrayLattice<Float>(wGriddedData);
     901         228 :     wLattice = wArrayLattice;
     902         228 :     AlwaysAssert(wLattice, AipsError);
     903             : 
     904             :     // clipping related stuff
     905         228 :     if (clipminmax_) {
     906          16 :         gmin_.resize(gridShape);
     907          16 :         gmin_ = Complex(FLT_MAX);
     908          16 :         gmax_.resize(gridShape);
     909          16 :         gmax_ = Complex(-FLT_MAX);
     910          16 :         wmin_.resize(gridShape);
     911          16 :         wmin_ = 0.0f;
     912          16 :         wmax_.resize(gridShape);
     913          16 :         wmax_ = 0.0f;
     914          16 :         npoints_.resize(gridShape);
     915          16 :         npoints_ = 0;
     916             :     }
     917             : 
     918             :     // debug messages
     919         684 :     LogOrigin msgOrigin("SDGrid", "initializeToSky", WHERE);
     920         228 :     auto & logger = logIO();
     921         228 :     logger << msgOrigin << LogIO::DEBUGGING;
     922         228 :     logger.output() << "clipminmax_ = " << std::boolalpha << clipminmax_
     923         228 :                     << " (" << std::noboolalpha << clipminmax_ << ")";
     924         228 :     logger << LogIO::POST;
     925         228 :     if (clipminmax_) {
     926             :         logger << msgOrigin << LogIO::DEBUGGING
     927             :                << "will use clipping-capable Fortran gridder ggridsd2 for imaging"
     928          16 :                << LogIO::POST;
     929             :     }
     930         228 : }
     931             : 
     932         228 : void SDGrid::finalizeToSky()
     933             : {
     934         228 :     if (pointingToImage) delete pointingToImage;
     935         228 :     pointingToImage = nullptr;
     936         228 : }
     937             : 
     938           0 : Array<Complex>* SDGrid::getDataPointer(const IPosition& centerLoc2D,
     939             :                                        Bool readonly) {
     940             :   Array<Complex>* result;
     941             :   // Is tiled: get tiles and set up offsets
     942           0 :   centerLoc(0)=centerLoc2D(0);
     943           0 :   centerLoc(1)=centerLoc2D(1);
     944           0 :   result=&imageCache->tile(offsetLoc, centerLoc, readonly);
     945           0 :   return result;
     946             : }
     947           0 : Array<Float>* SDGrid::getWDataPointer(const IPosition& centerLoc2D,
     948             :                                       Bool readonly) {
     949             :   Array<Float>* result;
     950             :   // Is tiled: get tiles and set up offsets
     951           0 :   centerLoc(0)=centerLoc2D(0);
     952           0 :   centerLoc(1)=centerLoc2D(1);
     953           0 :   result=&wImageCache->tile(offsetLoc, centerLoc, readonly);
     954           0 :   return result;
     955             : }
     956             : 
     957             : #define NEED_UNDERSCORES
     958             : #if defined(NEED_UNDERSCORES)
     959             : #define ggridsd ggridsd_
     960             : #define dgridsd dgridsd_
     961             : #define ggridsdclip ggridsdclip_
     962             : #endif
     963             : 
     964             : extern "C" {
     965             :    void ggridsd(Double*,
     966             :                 const Complex*,
     967             :                 Int*,
     968             :                 Int*,
     969             :                 Int*,
     970             :                 const Int*,
     971             :                 const Int*,
     972             :                 const Float*,
     973             :                 Int*,
     974             :                 Int*,
     975             :                 Complex*,
     976             :                 Float*,
     977             :                 Int*,
     978             :                 Int*,
     979             :                 Int *,
     980             :                 Int *,
     981             :                 Int*,
     982             :                 Int*,
     983             :                 Float*,
     984             :                 Int*,
     985             :                 Int*,
     986             :                 Double*);
     987             :    void ggridsdclip(Double*,
     988             :                  const Complex*,
     989             :                  Int*,
     990             :                  Int*,
     991             :                  Int*,
     992             :                  const Int*,
     993             :                  const Int*,
     994             :                  const Float*,
     995             :                  Int*,
     996             :                  Int*,
     997             :                  Complex*,
     998             :                  Float*,
     999             :                  Int*,
    1000             :                  Complex*,
    1001             :                  Float*,
    1002             :                  Complex*,
    1003             :                  Float*,
    1004             :                  Int*,
    1005             :                  Int*,
    1006             :                  Int *,
    1007             :                  Int *,
    1008             :                  Int*,
    1009             :                  Int*,
    1010             :                  Float*,
    1011             :                  Int*,
    1012             :                  Int*,
    1013             :                  Double*);
    1014             :    void dgridsd(Double*,
    1015             :                 Complex*,
    1016             :                 Int*,
    1017             :                 Int*,
    1018             :                 const Int*,
    1019             :                 const Int*,
    1020             :                 Int*,
    1021             :                 Int*,
    1022             :                 const Complex*,
    1023             :                 Int*,
    1024             :                 Int*,
    1025             :                 Int *,
    1026             :                 Int *,
    1027             :                 Int*,
    1028             :                 Int*,
    1029             :                 Float*,
    1030             :                 Int*,
    1031             :                 Int*);
    1032             : }
    1033             : 
    1034        4322 : void SDGrid::put(const VisBuffer& vb, Int row, Bool dopsf,
    1035             :         FTMachine::Type type)
    1036             : {
    1037        8644 :     LogIO os(LogOrigin("SDGrid", "put"));
    1038             : 
    1039        4322 :     gridOk(convSupport);
    1040             : 
    1041             :     // Check if ms has changed then cache new spw and chan selection
    1042        4322 :     if (vb.newMS()) {
    1043             :         #if defined(SDGRID_PERFS)
    1044          43 :         StartStop trigger(cMatchAllSpwChans);
    1045             :         #endif
    1046          43 :         matchAllSpwChans(vb);
    1047          43 :         lastIndex_p = 0;
    1048          43 :         if (lastIndexPerAnt_p.nelements() < (size_t)vb.numberAnt()) {
    1049           0 :             lastIndexPerAnt_p.resize(vb.numberAnt());
    1050             :         }
    1051          43 :         lastIndexPerAnt_p = 0;
    1052             :     }
    1053             : 
    1054             :     // Here we redo the match or use previous match
    1055             :     // Channel matching for the actual spectral window of buffer
    1056        4322 :     if (doConversion_p[vb.spectralWindow()]) {
    1057             :         #if defined(SDGRID_PERFS)
    1058         964 :         StartStop trigger(cMatchChannel);
    1059             :         #endif
    1060         964 :         matchChannel(vb.spectralWindow(), vb);
    1061             :     }
    1062             :     else {
    1063        3358 :         chanMap.resize();
    1064        3358 :         chanMap = multiChanMap_p[vb.spectralWindow()];
    1065             :     }
    1066             : 
    1067             :     // No point in reading data if its not matching in frequency
    1068        4322 :     if (max(chanMap)==-1)
    1069           0 :       return;
    1070             : 
    1071        8644 :     Matrix<Float> imagingweight;
    1072        4322 :     pickWeights(vb, imagingweight);
    1073             : 
    1074        4322 :     if (type==FTMachine::PSF || type==FTMachine::COVERAGE)
    1075        2161 :         dopsf = true;
    1076        4322 :     if (dopsf) type=FTMachine::PSF;
    1077             : 
    1078        8644 :     Cube<Complex> data;
    1079             :     //Fortran gridder need the flag as ints
    1080        8644 :     Cube<Int> flags;
    1081        8644 :     Matrix<Float> elWeight;
    1082             :     {
    1083             :         #if defined(SDGRID_PERFS)
    1084        8644 :         StartStop trigger(cInterpolateFrequencyToGrid);
    1085             :         #endif
    1086        4322 :         interpolateFrequencyTogrid(vb, imagingweight,data, flags, elWeight, type);
    1087             :     }
    1088             : 
    1089             :     Bool iswgtCopy;
    1090             :     const Float *wgtStorage;
    1091        4322 :     wgtStorage=elWeight.getStorage(iswgtCopy);
    1092             :     Bool isCopy;
    1093        4322 :     const Complex *datStorage = nullptr;
    1094        4322 :     if (!dopsf)
    1095        2161 :         datStorage = data.getStorage(isCopy);
    1096             : 
    1097             :     // If row is -1 then we pass through all rows
    1098             :     Int startRow, endRow, nRow;
    1099        4322 :     if (row == -1) {
    1100        4322 :         nRow = vb.nRow();
    1101        4322 :         startRow = 0;
    1102        4322 :         endRow = nRow - 1;
    1103             :     } else {
    1104           0 :         nRow = 1;
    1105           0 :         startRow = endRow = row;
    1106             :     }
    1107             : 
    1108        8644 :     Vector<Int> rowFlags(vb.flagRow().nelements(),0);
    1109      356400 :     for (Int rownr=startRow; rownr<=endRow; rownr++) {
    1110      352078 :         if (vb.flagRow()(rownr)) rowFlags(rownr) = 1;
    1111             :     }
    1112             : 
    1113             :     // Take care of translation of Bools to Integer
    1114        4322 :     Int idopsf = dopsf ? 1 : 0;
    1115             : 
    1116             :     /*if(isTiled) {
    1117             :     }
    1118             :     else*/
    1119             :     {
    1120        8644 :         Matrix<Double> xyPositions(2, endRow - startRow + 1);
    1121        4322 :         xyPositions = -1e9; // make sure failed getXYPos does not fall on grid
    1122      356400 :         for (Int rownr=startRow; rownr<=endRow; rownr++) {
    1123      352078 :             if (getXYPos(vb, rownr)) {
    1124      352078 :                 xyPositions(0, rownr) = xyPos(0);
    1125      352078 :                 xyPositions(1, rownr) = xyPos(1);
    1126             :             }
    1127             :         }
    1128             :         {
    1129             :             #if defined(SDGRID_PERFS)
    1130        8644 :             StartStop trigger(cGridData);
    1131             :             #endif
    1132             :             Bool del;
    1133             :             //      IPosition s(data.shape());
    1134        4322 :             const IPosition& fs=flags.shape();
    1135        8644 :             std::vector<Int> s(fs.begin(), fs.end());
    1136             :             Bool datCopy, wgtCopy;
    1137        4322 :             Complex * datStor=griddedData.getStorage(datCopy);
    1138        4322 :             Float * wgtStor=wGriddedData.getStorage(wgtCopy);
    1139             : 
    1140        4322 :             Bool call_ggridsd = !clipminmax_ || dopsf;
    1141             : 
    1142        4322 :             if (call_ggridsd) {
    1143             : 
    1144        8620 :                 ggridsd(xyPositions.getStorage(del),
    1145             :                     datStorage,
    1146        4310 :                     &s[0],
    1147        4310 :                     &s[1],
    1148             :                     &idopsf,
    1149        4310 :                     flags.getStorage(del),
    1150        4310 :                     rowFlags.getStorage(del),
    1151             :                     wgtStorage,
    1152        4310 :                     &s[2],
    1153             :                     &row,
    1154             :                     datStor,
    1155             :                     wgtStor,
    1156             :                     &nx,
    1157             :                     &ny,
    1158             :                     &npol,
    1159             :                     &nchan,
    1160             :                     &convSupport,
    1161             :                     &convSampling,
    1162             :                     convFunc.getStorage(del),
    1163             :                     chanMap.getStorage(del),
    1164             :                     polMap.getStorage(del),
    1165             :                     sumWeight.getStorage(del));
    1166             : 
    1167             :             }
    1168             :             else {
    1169             :                 Bool gminCopy;
    1170          12 :                 Complex *gminStor = gmin_.getStorage(gminCopy);
    1171             :                 Bool gmaxCopy;
    1172          12 :                 Complex *gmaxStor = gmax_.getStorage(gmaxCopy);
    1173             :                 Bool wminCopy;
    1174          12 :                 Float *wminStor = wmin_.getStorage(wminCopy);
    1175             :                 Bool wmaxCopy;
    1176          12 :                 Float *wmaxStor = wmax_.getStorage(wmaxCopy);
    1177             :                 Bool npCopy;
    1178          12 :                 Int *npStor = npoints_.getStorage(npCopy);
    1179             : 
    1180          24 :                 ggridsdclip(xyPositions.getStorage(del),
    1181             :                     datStorage,
    1182          12 :                     &s[0],
    1183          12 :                     &s[1],
    1184             :                     &idopsf,
    1185          12 :                     flags.getStorage(del),
    1186          12 :                     rowFlags.getStorage(del),
    1187             :                     wgtStorage,
    1188          12 :                     &s[2],
    1189             :                     &row,
    1190             :                     datStor,
    1191             :                     wgtStor,
    1192             :                     npStor,
    1193             :                     gminStor,
    1194             :                     wminStor,
    1195             :                     gmaxStor,
    1196             :                     wmaxStor,
    1197             :                     &nx,
    1198             :                     &ny,
    1199             :                     &npol,
    1200             :                     &nchan,
    1201             :                     &convSupport,
    1202             :                     &convSampling,
    1203             :                     convFunc.getStorage(del),
    1204             :                     chanMap.getStorage(del),
    1205             :                     polMap.getStorage(del),
    1206             :                     sumWeight.getStorage(del));
    1207             : 
    1208          12 :                 gmin_.putStorage(gminStor, gminCopy);
    1209          12 :                 gmax_.putStorage(gmaxStor, gmaxCopy);
    1210          12 :                 wmin_.putStorage(wminStor, wminCopy);
    1211          12 :                 wmax_.putStorage(wmaxStor, wmaxCopy);
    1212          12 :                 npoints_.putStorage(npStor, npCopy);
    1213             :             }
    1214        4322 :             griddedData.putStorage(datStor, datCopy);
    1215        4322 :             wGriddedData.putStorage(wgtStor, wgtCopy);
    1216             :         }
    1217             :     }
    1218        4322 :     if (!dopsf)
    1219        2161 :         data.freeStorage(datStorage, isCopy);
    1220        4322 :     elWeight.freeStorage(wgtStorage,iswgtCopy);
    1221             : }
    1222             : 
    1223         338 : void SDGrid::get(VisBuffer& vb, Int row)
    1224             : {
    1225         676 :   LogIO os(LogOrigin("SDGrid", "get"));
    1226             : 
    1227         338 :   gridOk(convSupport);
    1228             : 
    1229             :   // If row is -1 then we pass through all rows
    1230             :   Int startRow, endRow, nRow;
    1231         338 :   if (row==-1) {
    1232         338 :     nRow=vb.nRow();
    1233         338 :     startRow=0;
    1234         338 :     endRow=nRow-1;
    1235         338 :     vb.modelVisCube()=Complex(0.0,0.0);
    1236             :   } else {
    1237           0 :     nRow=1;
    1238           0 :     startRow=row;
    1239           0 :     endRow=row;
    1240           0 :     vb.modelVisCube().xyPlane(row)=Complex(0.0,0.0);
    1241             :   }
    1242             : 
    1243             : 
    1244             :   //Check if ms has changed then cache new spw and chan selection
    1245         338 :   if(vb.newMS()){
    1246           0 :     matchAllSpwChans(vb);
    1247           0 :     lastIndex_p=0;
    1248           0 :     if (lastIndexPerAnt_p.nelements() < (size_t)vb.numberAnt()) {
    1249           0 :       lastIndexPerAnt_p.resize(vb.numberAnt());
    1250             :     }
    1251           0 :     lastIndexPerAnt_p=0;
    1252             :   }
    1253             : 
    1254             :   //Here we redo the match or use previous match
    1255             : 
    1256             :   //Channel matching for the actual spectral window of buffer
    1257         338 :   if(doConversion_p[vb.spectralWindow()]){
    1258           0 :     matchChannel(vb.spectralWindow(), vb);
    1259             :   }
    1260             :   else{
    1261         338 :     chanMap.resize();
    1262         338 :     chanMap=multiChanMap_p[vb.spectralWindow()];
    1263             :   }
    1264             : 
    1265             :   //No point in reading data if its not matching in frequency
    1266         338 :   if(max(chanMap)==-1)
    1267           0 :     return;
    1268         676 :   Cube<Complex> data;
    1269         676 :   Cube<Int> flags;
    1270         338 :   getInterpolateArrays(vb, data, flags);
    1271             : 
    1272             :   Complex *datStorage;
    1273             :   Bool isCopy;
    1274         338 :   datStorage=data.getStorage(isCopy);
    1275             :   // NOTE: with MS V2.0 the pointing could change per antenna and timeslot
    1276             :   //
    1277         676 :   Vector<Int> rowFlags(vb.flagRow().nelements());
    1278         338 :   rowFlags=0;
    1279        3346 :   for (Int rownr=startRow; rownr<=endRow; rownr++) {
    1280        3008 :     if(vb.flagRow()(rownr)) rowFlags(rownr)=1;
    1281             :     //single dish yes ?
    1282        3008 :     if(max(vb.uvw()(rownr).vector()) > 0.0) rowFlags(rownr)=1;
    1283             :   }
    1284             : 
    1285             : 
    1286             :   /*if(isTiled) {
    1287             : 
    1288             :     for (Int rownr=startRow; rownr<=endRow; rownr++) {
    1289             : 
    1290             :       if(getXYPos(vb, rownr)) {
    1291             : 
    1292             :           // Get the tile
    1293             :         IPosition centerLoc2D(2, Int(xyPos(0)), Int(xyPos(1)));
    1294             :         Array<Complex>* dataPtr=getDataPointer(centerLoc2D, true);
    1295             :         Int aNx=dataPtr->shape()(0);
    1296             :         Int aNy=dataPtr->shape()(1);
    1297             : 
    1298             :         // Now use FORTRAN to do the gridding. Remember to
    1299             :         // ensure that the shape and offsets of the tile are
    1300             :         // accounted for.
    1301             :         Bool del;
    1302             :         Vector<Double> actualPos(2);
    1303             :         for (Int i=0;i<2;i++) {
    1304             :           actualPos(i)=xyPos(i)-Double(offsetLoc(i));
    1305             :         }
    1306             :         //      IPosition s(data.shape());
    1307             :         const IPosition& fs=data.shape();
    1308             :         std::vector<Int> s(fs.begin(), fs.end());
    1309             : 
    1310             :         dgridsd(actualPos.getStorage(del),
    1311             :                 datStorage,
    1312             :                 &s[0],
    1313             :                 &s[1],
    1314             :                 flags.getStorage(del),
    1315             :                 rowFlags.getStorage(del),
    1316             :                 &s[2],
    1317             :                 &rownr,
    1318             :                 dataPtr->getStorage(del),
    1319             :                 &aNx,
    1320             :                 &aNy,
    1321             :                 &npol,
    1322             :                 &nchan,
    1323             :                 &convSupport,
    1324             :                 &convSampling,
    1325             :                 convFunc.getStorage(del),
    1326             :                 chanMap.getStorage(del),
    1327             :                 polMap.getStorage(del));
    1328             :       }
    1329             :     }
    1330             :   }
    1331             :   else*/
    1332             :   {
    1333         676 :     Matrix<Double> xyPositions(2, endRow-startRow+1);
    1334         338 :     xyPositions=-1e9;
    1335        3346 :     for (Int rownr=startRow; rownr<=endRow; rownr++) {
    1336        3008 :       if(getXYPos(vb, rownr)) {
    1337        3008 :         xyPositions(0, rownr)=xyPos(0);
    1338        3008 :         xyPositions(1, rownr)=xyPos(1);
    1339             :       }
    1340             :     }
    1341             : 
    1342             :     Bool del;
    1343             :     //    IPosition s(data.shape());
    1344         338 :     const IPosition& fs=data.shape();
    1345         676 :     std::vector<Int> s(fs.begin(), fs.end());
    1346         676 :     dgridsd(xyPositions.getStorage(del),
    1347             :             datStorage,
    1348         338 :             &s[0],
    1349         338 :             &s[1],
    1350         338 :             flags.getStorage(del),
    1351         338 :             rowFlags.getStorage(del),
    1352         338 :             &s[2],
    1353             :             &row,
    1354         338 :             griddedData.getStorage(del),
    1355             :             &nx,
    1356             :             &ny,
    1357             :             &npol,
    1358             :             &nchan,
    1359             :             &convSupport,
    1360             :             &convSampling,
    1361             :             convFunc.getStorage(del),
    1362             :             chanMap.getStorage(del),
    1363             :             polMap.getStorage(del));
    1364             : 
    1365         338 :     data.putStorage(datStorage, isCopy);
    1366             :   }
    1367         338 :   interpolateFrequencyFromgrid(vb, data, FTMachine::MODEL);
    1368             : }
    1369             : 
    1370             : // Helper functions for SDGrid::makeImage
    1371             : namespace {
    1372             : inline
    1373        4322 : void setupVisBufferForFTMachineType(FTMachine::Type type, VisBuffer& vb) {
    1374        4322 :     switch(type) {
    1375           0 :     case FTMachine::RESIDUAL:
    1376           0 :         vb.visCube() = vb.correctedVisCube();
    1377           0 :         vb.visCube() -= vb.modelVisCube();
    1378           0 :         break;
    1379           0 :     case FTMachine::PSF:
    1380           0 :         vb.visCube() = Complex(1.0,0.0);
    1381           0 :         break;
    1382        2161 :     case FTMachine::COVERAGE:
    1383        2161 :         vb.visCube() = Complex(1.0);
    1384        2161 :         break;
    1385        2161 :     default:
    1386        2161 :         break;
    1387             :     }
    1388        4322 : }
    1389             : 
    1390             : inline
    1391         258 : void getParamsForFTMachineType(const ROVisibilityIterator& vi, FTMachine::Type in_type,
    1392             :           casacore::Bool& out_dopsf, FTMachine::Type& out_type) {
    1393             : 
    1394             :     // Tune input type of FTMachine
    1395         258 :     auto haveCorrectedData = not (vi.msColumns().correctedData().isNull());
    1396         258 :     auto tunedType =
    1397         258 :             ((in_type == FTMachine::CORRECTED) && (not haveCorrectedData)) ?
    1398             :             FTMachine::OBSERVED : in_type;
    1399             : 
    1400             :     // Compute output parameters
    1401         258 :     switch(tunedType) {
    1402          65 :     case FTMachine::RESIDUAL:
    1403             :     case FTMachine::MODEL:
    1404             :     case FTMachine::CORRECTED:
    1405          65 :         out_dopsf = false;
    1406          65 :         out_type = tunedType;
    1407          65 :         break;
    1408         129 :     case FTMachine::PSF:
    1409             :     case FTMachine::COVERAGE:
    1410         129 :         out_dopsf = true;
    1411         129 :         out_type = tunedType;
    1412         129 :         break;
    1413          64 :     default:
    1414          64 :         out_dopsf = false;
    1415          64 :         out_type = FTMachine::OBSERVED;
    1416          64 :         break;
    1417             :     }
    1418         258 : }
    1419             : 
    1420        1186 : void abortOnPolFrameChange(const StokesImageUtil::PolRep refPolRep, const String & refMsName, ROVisibilityIterator &vi) {
    1421        1186 :     auto vb = vi.getVisBuffer();
    1422        1186 :     const auto polRep = (vb->polFrame() == MSIter::Linear) ?
    1423        1186 :             StokesImageUtil::LINEAR : StokesImageUtil::CIRCULAR;
    1424        1186 :     const auto polFrameChanged = (polRep != refPolRep);
    1425        1186 :     if (polFrameChanged) {
    1426             :         // Time of polarization change
    1427           0 :         constexpr auto timeColEnum = MS::PredefinedColumns::TIME;
    1428           0 :         const auto & timeColName = MS::columnName(timeColEnum);
    1429           0 :         const auto timeVbFirstRow = vb->time()[0];
    1430             : 
    1431           0 :         ScalarMeasColumn<MEpoch> timeMeasCol(vi.ms(),timeColName);
    1432           0 :         const auto & timeMeasRef = timeMeasCol.getMeasRef();
    1433             : 
    1434           0 :         const auto & timeUnit = MS::columnUnit(timeColEnum);
    1435             : 
    1436           0 :         MEpoch polFrameChangeEpoch(Quantity(timeVbFirstRow,timeUnit),
    1437           0 :                                    timeMeasRef);
    1438           0 :         MVTime polFrameChangeTime(polFrameChangeEpoch.getValue());
    1439             : 
    1440             :         // Error message
    1441           0 :         MVTime::Format fmt(MVTime::YMD | MVTime::USE_SPACE,10);
    1442           0 :         constexpr auto nl = '\n';
    1443           0 :         stringstream msg;
    1444             :         msg  << "Polarization Frame changed ! " << nl
    1445           0 :                 << setw(9) << right << "from: " << setw(8) << left << StokesImageUtil::toString(refPolRep)
    1446           0 :                 << " in: " << refMsName << nl
    1447           0 :                 << setw(9) << right << "to: "   << setw(8) << left << StokesImageUtil::toString(polRep)
    1448           0 :                 << " at: " << MVTime::Format(fmt) << polFrameChangeTime
    1449           0 :                 << " (" << fixed << setprecision(6) << polFrameChangeTime.second() << " s)"
    1450           0 :                 << " in: " << vb->msName();
    1451             : 
    1452           0 :         LogOrigin logOrigin("","abortOnPolFrameChange()");
    1453           0 :         LogIO logger(logOrigin);
    1454           0 :         logger << msg.str() << LogIO::SEVERE << LogIO::POST;
    1455             : 
    1456             :         // Abort
    1457           0 :         logger.sourceLocation(WHERE);
    1458           0 :         logger << "Polarization Frame must not change" << LogIO::EXCEPTION;
    1459             :     };
    1460        1186 : }
    1461             : 
    1462             : } // SDGrid::makeImage helper functions namespace
    1463             : 
    1464        1186 : void SDGrid::nextChunk(ROVisibilityIterator &vi) {
    1465             : #if defined(SDGRID_PERFS)
    1466        2372 :     StartStop trigger(cNextChunk);
    1467             : #endif
    1468        1186 :     vi.nextChunk();
    1469        1186 : }
    1470             : 
    1471             : // Make a plain straightforward honest-to-FSM image. This returns
    1472             : // a complex image, without conversion to Stokes. The representation
    1473             : // is that required for the visibilities.
    1474             : //----------------------------------------------------------------------
    1475         228 : void SDGrid::makeImage(FTMachine::Type inType,
    1476             :                 ROVisibilityIterator& vi,
    1477             :                 ImageInterface<Complex>& theImage,
    1478             :                 Matrix<Float>& weight) {
    1479             : 
    1480             :     // Attach visibility buffer (VisBuffer) to visibility iterator (VisibilityIterator)
    1481         456 :     VisBuffer vb(vi);
    1482             : 
    1483             :     // Set the Polarization Representation
    1484             :     // of image's Stokes Coordinate Axis
    1485             :     // based on first data in first MS
    1486         228 :     vi.origin();
    1487         228 :     const auto imgPolRep = (vb.polFrame() == MSIter::Linear) ?
    1488         228 :             StokesImageUtil::LINEAR : StokesImageUtil::CIRCULAR;
    1489         228 :     StokesImageUtil::changeCStokesRep(theImage, imgPolRep);
    1490         456 :     const auto firstMsName = vb.msName();
    1491             : 
    1492         228 :     initializeToSky(theImage, weight, vb);
    1493             : 
    1494             :     // Setup SDGrid Cache Manager
    1495         228 :     const auto onDuty = cacheIsEnabled;
    1496         228 :     const auto accessMode = cache.isEmpty() ? Cache::AccessMode::WRITE
    1497         228 :                                             : Cache::AccessMode::READ;
    1498         456 :     CacheManager cacheManager(cache, onDuty, accessMode);
    1499             : 
    1500             :     // Loop over the visibilities, putting VisBuffers
    1501        1414 :     for (vi.originChunks(); vi.moreChunks(); nextChunk(vi)) {
    1502        1186 :         abortOnPolFrameChange(imgPolRep, firstMsName, vi);
    1503             :         FTMachine::Type actualType;
    1504             :         Bool doPSF;
    1505        1186 :         if (vi.newMS()) { // Note: the first MS is a new MS
    1506         258 :             getParamsForFTMachineType(vi, inType, doPSF, actualType);
    1507         258 :             handleNewMs(vi, theImage);
    1508             :         }
    1509        5508 :         for (vi.origin(); vi.more(); vi++) {
    1510        4322 :             setupVisBufferForFTMachineType(actualType, vb);
    1511        4322 :             constexpr Int allVbRows = -1;
    1512        4322 :             put(vb, allVbRows, doPSF, actualType);
    1513             :         }
    1514             :     }
    1515         228 :     finalizeToSky();
    1516             : 
    1517             :     // Normalize by dividing out weights, etc.
    1518         228 :     auto doNormalize = (inType != FTMachine::COVERAGE);
    1519         228 :     getImage(weight, doNormalize);
    1520             : 
    1521             :     // Warning message
    1522         228 :     if (allEQ(weight, 0.0f)) {
    1523           6 :         LogIO logger(LogOrigin(name(),"makeImage"));
    1524             :         logger << LogIO::SEVERE
    1525             :                 << "No useful data in SDGrid: all weights are zero"
    1526           2 :                 << LogIO::POST;
    1527             :     }
    1528         228 : }
    1529             : 
    1530             : // Finalize : optionally normalize by weight image
    1531         228 : ImageInterface<Complex>& SDGrid::getImage(Matrix<Float>& weights,
    1532             :                                           Bool normalize)
    1533             : {
    1534         228 :   AlwaysAssert(lattice, AipsError);
    1535         228 :   AlwaysAssert(image, AipsError);
    1536             : 
    1537         228 :   logIO() << LogOrigin("SDGrid", "getImage") << LogIO::NORMAL;
    1538             : 
    1539             :   // execute minmax clipping
    1540         228 :   clipMinMax();
    1541             : 
    1542         228 :   weights.resize(sumWeight.shape());
    1543             : 
    1544         228 :   convertArray(weights,sumWeight);
    1545             : 
    1546             :   // If the weights are all zero then we cannot normalize
    1547             :   // otherwise we don't care.
    1548             :   ///////////////////////
    1549             :   /*{
    1550             :   PagedImage<Float> thisScreen(lattice->shape(), image->coordinates(), "TheData");
    1551             :   LatticeExpr<Float> le(abs(*lattice));
    1552             :   thisScreen.copyData(le);
    1553             :   PagedImage<Float> thisScreen2(lattice->shape(), image->coordinates(), "TheWeight");
    1554             :   LatticeExpr<Float> le2(abs(*wLattice));
    1555             :   thisScreen2.copyData(le2);
    1556             :   }*/
    1557             :   /////////////////////
    1558             : 
    1559         228 :   if(normalize) {
    1560         114 :     if(max(weights)==0.0) {
    1561             :       //logIO() << LogIO::WARN << "No useful data in SDGrid: weights all zero"
    1562             :       //              << LogIO::POST;
    1563             :       //image->set(Complex(0.0));
    1564           1 :       return *image;
    1565             :     }
    1566             :     //Timer tim;
    1567             :     //tim.mark();
    1568             :     //lattice->copyData((LatticeExpr<Complex>)(iif((*wLattice<=minWeight_p), 0.0,
    1569             :     //                                           (*lattice)/(*wLattice))));
    1570             :     //As we are not using disk based lattices anymore the above uses too much memory for
    1571             :     // ArrayLattice...it does not do a real  inplace math but rather mutiple copies
    1572             :     // seem to be involved  thus the less elegant but faster and less memory hog loop
    1573             :     // below.
    1574             : 
    1575         226 :     IPosition pos(4);
    1576        7326 :     for (Int chan=0; chan < nchan; ++chan){
    1577        7213 :       pos[3]=chan;
    1578       14467 :       for( Int pol=0; pol < npol; ++ pol){
    1579        7254 :         pos[2]=pol;
    1580      455875 :         for (Int y=0; y < ny ; ++y){
    1581      448621 :           pos[1]=y;
    1582    34433263 :           for (Int x=0; x < nx; ++x){
    1583    33984642 :             pos[0]=x;
    1584    33984642 :             Float wgt=wGriddedData(pos);
    1585    33984642 :             if(wgt > minWeight_p)
    1586    26113193 :               griddedData(pos)=griddedData(pos)/wgt;
    1587             :             else
    1588     7871449 :               griddedData(pos)=0.0;
    1589             :           }
    1590             :         }
    1591             :       }
    1592             :       }
    1593             :     //tim.show("After normalizing");
    1594             :   }
    1595             : 
    1596             :   //if(!isTiled)
    1597             :   {
    1598             :     // Now find the SubLattice corresponding to the image
    1599         454 :     IPosition gridShape(4, nx, ny, npol, nchan);
    1600         454 :     IPosition blc(4, (nx-image->shape()(0)+(nx%2==0))/2,
    1601         681 :                   (ny-image->shape()(1)+(ny%2==0))/2, 0, 0);
    1602         454 :     IPosition stride(4, 1);
    1603         681 :     IPosition trc(blc+image->shape()-stride);
    1604         454 :     LCBox gridBox(blc, trc, gridShape);
    1605         681 :     SubLattice<Complex> gridSub(*arrayLattice, gridBox);
    1606             : 
    1607             :     // Do the copy
    1608         227 :     image->copyData(gridSub);
    1609             :   }
    1610         227 :   return *image;
    1611             : }
    1612             : 
    1613             : // Return weights image
    1614           0 : void SDGrid::getWeightImage(ImageInterface<Float>& weightImage, Matrix<Float>& weights)
    1615             : {
    1616           0 :   AlwaysAssert(lattice, AipsError);
    1617           0 :   AlwaysAssert(image, AipsError);
    1618             : 
    1619           0 :   logIO() << LogOrigin("SDGrid", "getWeightImage") << LogIO::NORMAL;
    1620             : 
    1621           0 :   weights.resize(sumWeight.shape());
    1622           0 :   convertArray(weights,sumWeight);
    1623             : 
    1624           0 :   weightImage.copyData(*wArrayLattice);
    1625           0 : }
    1626             : 
    1627         476 : void SDGrid::ok() {
    1628         476 :     AlwaysAssert(image, AipsError);
    1629         476 : }
    1630             : 
    1631             : // Get the index into the pointing table for this time. Note that the
    1632             : // in the pointing table, TIME specifies the beginning of the spanned
    1633             : // time range, whereas for the main table, TIME is the centroid.
    1634             : // Note that the behavior for multiple matches is not specified! i.e.
    1635             : // if there are multiple matches, the index returned depends on the
    1636             : // history of previous matches. It is deterministic but not obvious.
    1637             : // One could cure this by searching but it would be considerably
    1638             : // costlier.
    1639      179093 : Int SDGrid::getIndex(const MSPointingColumns& mspc, const Double& time,
    1640             :                      const Double& interval, const Int& antid) {
    1641             :   //Int start=lastIndex_p;
    1642      179093 :   Int start=lastIndexPerAnt_p[antid];
    1643      179093 :   Double tol=interval < 0.0 ? time*C::dbl_epsilon : interval/2.0;
    1644             :   // Search forwards
    1645      179093 :   Int nrows=mspc.time().nrow();
    1646      402416 :   for (Int i=start;i<nrows;i++) {
    1647             :     // Check for ANTENNA_ID. When antid<0 (default) ANTENNA_ID in POINTING table < 0 is ignored.
    1648             :     // MS v2 definition indicates ANTENNA_ID in POINING >= 0.
    1649      402398 :     if (antid >= 0 && mspc.antennaId()(i) != antid) {
    1650           0 :       continue;
    1651             :     }
    1652             : 
    1653      402398 :     Double midpoint = mspc.time()(i); // time in POINTING table is midpoint
    1654             :     // If the interval in the pointing table is negative, use the last
    1655             :     // entry. Note that this may be invalid (-1) but in that case
    1656             :     // the calling routine will generate an error
    1657      402398 :     Double mspc_interval = mspc.interval()(i);
    1658             : 
    1659      402398 :     if(mspc_interval<0.0) {
    1660             :       //return lastIndex_p;
    1661           0 :       return lastIndexPerAnt_p[antid];
    1662             :     }
    1663             :     // Pointing table interval is specified so we have to do a match
    1664             :     else {
    1665             :       // Is the midpoint of this pointing table entry within the specified
    1666             :       // tolerance of the main table entry?
    1667      402398 :       if(abs(midpoint-time) <= (mspc_interval/2.0+tol)) {
    1668             :         //lastIndex_p=i;
    1669      179075 :         lastIndexPerAnt_p[antid]=i;
    1670      179075 :         return i;
    1671             :       }
    1672             :     }
    1673             :   }
    1674             :   // Search backwards
    1675       69174 :   for (Int i=start;i>=0;i--) {
    1676       69174 :     if (antid >= 0 && mspc.antennaId()(i) != antid) {
    1677           0 :       continue;
    1678             :     }
    1679       69174 :     Double midpoint = mspc.time()(i); // time in POINTING table is midpoint
    1680       69174 :     Double mspc_interval = mspc.interval()(i);
    1681       69174 :     if(mspc_interval<0.0) {
    1682             :       //return lastIndex_p;
    1683           0 :       return lastIndexPerAnt_p[antid];
    1684             :     }
    1685             :     // Pointing table interval is specified so we have to do a match
    1686             :     else {
    1687             :       // Is the midpoint of this pointing table entry within the specified
    1688             :       // tolerance of the main table entry?
    1689       69174 :       if(abs(midpoint-time) <= (mspc_interval/2.0+tol)) {
    1690             :         //lastIndex_p=i;
    1691          18 :   lastIndexPerAnt_p[antid]=i;
    1692          18 :         return i;
    1693             :       }
    1694             :     }
    1695             :   }
    1696             :   // No match!
    1697           0 :   return -1;
    1698             : }
    1699             : 
    1700      355086 : Bool SDGrid::getXYPos(const VisBuffer& vb, Int row) {
    1701             : 
    1702             :     // Cache control
    1703      355086 :     if (cacheIsEnabled and cache.isReadable()) {
    1704      176039 :         cache.loadRowPixel();
    1705      176039 :         return rowPixel.isValid;
    1706             :     }
    1707      179047 :     const auto onDuty = cacheIsEnabled and cache.isWriteable();
    1708      358094 :     CacheWriter cacheWriter(cache, onDuty);
    1709             : 
    1710             :     // Until we manage to compute a valid one ...
    1711      179047 :     rowPixel.isValid = false;
    1712             : 
    1713             :     // Select the POINTING table (columns) we'll work with.
    1714      179047 :     const auto haveConvertedColumn = ramPointingTable.nrow() > 0;
    1715      179047 :     const MSPointingColumns& pointingColumns = haveConvertedColumn ?
    1716           0 :               *ramPointingColumnsPtr
    1717      179047 :             : vb.msColumns().pointing();
    1718             : 
    1719      179047 :     const auto nPointings = pointingColumns.nrow();
    1720      179047 :     const auto havePointings = (nPointings >= 1);
    1721             : 
    1722             :     // We'll need to call these many times, so let's call them once for good
    1723      179047 :     const auto rowTime = vb.time()(row);
    1724      179047 :     const auto rowTimeInterval = vb.timeInterval()(row);
    1725      179047 :     const auto rowAntenna1 = vb.antenna1()(row);
    1726             : 
    1727             :     // 1. Try to find the index of a pointing recorded:
    1728             :     //     - for the antenna of specified row,
    1729             :     //     - at a time close enough to the time at which
    1730             :     //       data of specified row was taken using that antenna
    1731      179047 :     constexpr Int invalidIndex = -1;
    1732      179047 :     Int pointingIndex = invalidIndex;
    1733      179047 :     if (havePointings) {
    1734             :         #if defined(SDGRID_PERFS)
    1735      179047 :         StartStop trigger(cSearchValidPointing);
    1736             :         #endif
    1737             :         // if (vb.newMS())  vb.newMS does not work well using msid
    1738             :         // Note about above comment:
    1739             :         // - vb.newMS probably works well
    1740             :         // - but if the calling code is iterating over the rows of a subchunk
    1741             :         //   vb.newMS returns true for all rows belonging to the first subchunk
    1742             :         //   of the first chunk of a new MS.
    1743             : 
    1744             :         // ???
    1745             :         // What if vb changed since we were last called ?
    1746             :         // What if the calling code calls put and get, with different VisBuffers ?
    1747      179047 :         if (vb.msId() != msId_p) {
    1748         139 :             lastIndex_p = 0; // no longer used
    1749         139 :             if (lastIndexPerAnt_p.nelements() < (size_t)vb.numberAnt()) {
    1750          96 :                 lastIndexPerAnt_p.resize(vb.numberAnt());
    1751             :             }
    1752         139 :             lastIndexPerAnt_p = 0;
    1753         139 :             msId_p = vb.msId();
    1754         139 :             lastAntID_p = -1;
    1755             :         }
    1756             : 
    1757             :         // Try to locate a pointing verifying for specified row:
    1758             :         // | POINTING.TIME - MAIN.TIME | <= 0.5*(POINTING.INTERVAL + tolerance)
    1759             : 
    1760             :         // Try first using a tiny tolerance
    1761      179047 :         constexpr Double useTinyTolerance = -1.0;
    1762      179047 :         pointingIndex = getIndex(pointingColumns, rowTime, useTinyTolerance , rowAntenna1);
    1763             : 
    1764      179047 :         auto foundPointing = (pointingIndex >= 0);
    1765      179047 :         if (not foundPointing) {
    1766             :             // Try again using tolerance = MAIN.INTERVAL
    1767           0 :             pointingIndex = getIndex(pointingColumns, rowTime, rowTimeInterval, rowAntenna1);
    1768           0 :             foundPointing = (pointingIndex >= 0);
    1769             :         }
    1770             : 
    1771             :         // Making the implicit type conversion explicit.
    1772             :         // Conversion is safe because it occurs only when pointingIndex >= 0.
    1773      179047 :         const auto foundValidPointing = (foundPointing and (static_cast<rownr_t>(pointingIndex) < nPointings));
    1774             : 
    1775      179047 :         if (not foundValidPointing) {
    1776           0 :             ostringstream o;
    1777           0 :             o << "Failed to find pointing information for time "
    1778           0 :               << MVTime(rowTime/86400.0) << " : Omitting this point";
    1779             : 
    1780           0 :             logIO_p << LogIO::DEBUGGING << String(o) << LogIO::POST;
    1781             : 
    1782           0 :             return rowPixel.isValid;
    1783             :          }
    1784             :     }
    1785             : 
    1786             :     // 2. At this stage we have:
    1787             :     //        * either no pointings and an invalid pointingIndex
    1788             :     //        * or pointings and a valid pointingIndex.
    1789             :     //    Decide now if we need to interpolate antenna's pointing direction
    1790             :     //    at data-taking time:
    1791             :     //    we'll do so when data is sampled faster than pointings are recorded
    1792      179047 :     Bool needInterpolation = False;
    1793      179047 :     if (havePointings) {
    1794      179047 :         const auto pointingInterval = pointingColumns.interval()(pointingIndex);
    1795      179047 :         if (rowTimeInterval < pointingInterval) needInterpolation = True;
    1796             :     }
    1797      179047 :     const auto mustInterpolate = havePointings && needInterpolation;
    1798             : 
    1799             :     // 3. Create interpolator if needed
    1800      179047 :     if (mustInterpolate) {
    1801        5000 :         if (not isSplineInterpolationReady) {
    1802             :             #if defined(SDGRID_PERFS)
    1803           3 :             StartStop trigger(cComputeSplines);
    1804             :             #endif
    1805             :             const auto nAntennas = static_cast<size_t>(
    1806           3 :                 vb.msColumns().antenna().nrow()
    1807             :             );
    1808           3 :             interpolator = new SDPosInterpolator(
    1809             :                 pointingColumns,
    1810           3 :                 pointingDirCol_p,
    1811             :                 nAntennas
    1812           3 :             );
    1813           3 :             isSplineInterpolationReady = true;
    1814             :         } else {
    1815             :             // We have an interpolator. Re-use it if possible.
    1816        4997 :             const auto canReuseInterpolator = interpolator->inTimeRange(rowTime, rowAntenna1);
    1817        4997 :             if (not canReuseInterpolator) {
    1818             :                 // setup spline interpolator for the current dataset (CAS-11261, 2018/5/22 WK)
    1819             :                 // delete and re-create it
    1820           2 :                 delete interpolator;
    1821           2 :                 interpolator = 0;
    1822             :                 const auto nAntennas = static_cast<size_t>(
    1823           2 :                     vb.msColumns().antenna().nrow()
    1824             :                 );
    1825           2 :                 interpolator = new SDPosInterpolator(
    1826             :                     pointingColumns,
    1827           2 :                     pointingDirCol_p,
    1828             :                     nAntennas
    1829           2 :                 );
    1830             :             }
    1831             :         }
    1832             :     }
    1833             : 
    1834             :     // 4. Create the direction conversion machine if needed
    1835             : 
    1836      358094 :     if ( pointingDirCol_p == "SOURCE_OFFSET" or
    1837      179047 :          pointingDirCol_p == "POINTING_OFFSET" ) {
    1838             :         // It makes no sense to track in offset coordinates...
    1839             :         // hopefully the user sets the image coords right
    1840           0 :         fixMovingSource_p = false;
    1841             :     }
    1842             : 
    1843      179047 :     const auto needDirectionConverter = (
    1844      179047 :         not havePointings or not haveConvertedColumn or fixMovingSource_p
    1845             :     );
    1846             : 
    1847      179047 :     if (needDirectionConverter) {
    1848      179047 :         if (not pointingToImage) {
    1849             :             // Set the frame
    1850             :             const auto & rowAntenna1Position =
    1851         248 :                     vb.msColumns().antenna().positionMeas()(rowAntenna1);
    1852             :             // set dummy time stamp 1 day before rowTime
    1853         372 :             const MEpoch dummyEpoch(Quantity(rowTime - 86400.0, "s"));
    1854         124 :             mFrame_p = MeasFrame(dummyEpoch, rowAntenna1Position);
    1855             : 
    1856             :             // Remember antenna id for next call,
    1857             :             // which may be done using a different VisBuffer ...
    1858         124 :             lastAntID_p = rowAntenna1;
    1859             : 
    1860             :             // Compute the "model" required to setup the conversion machine
    1861         124 :             if (havePointings) {
    1862         248 :                 worldPosMeas = mustInterpolate ?
    1863             :                     directionMeas(pointingColumns, pointingIndex, rowTime)
    1864         124 :                   : directionMeas(pointingColumns, pointingIndex);
    1865             :             } else {
    1866             :                 // Without pointings, this sets the direction to the phase center
    1867           0 :                 worldPosMeas = vb.direction1()(row);
    1868             :             }
    1869             : 
    1870             :             // Make a machine to convert from the worldPosMeas to the output
    1871             :             // Direction Measure type for the relevant frame
    1872         248 :             MDirection::Ref outRef(directionCoord.directionType(), mFrame_p);
    1873         124 :             pointingToImage = new MDirection::Convert(worldPosMeas, outRef);
    1874         124 :             if (not pointingToImage) {
    1875           0 :                 logIO_p << "Cannot make direction conversion machine" << LogIO::EXCEPTION;
    1876             :             }
    1877             :             // Perform 1 dummy direction conversion to clear values
    1878             :             // cached in static variables of casacore functions like MeasTable::dUT1
    1879         124 :             MDirection _dir_tmp = (*pointingToImage)();
    1880             :         }
    1881             :     }
    1882             : 
    1883             :     // 5. Update the frame holding the measurements for this row
    1884      537141 :     const MEpoch rowEpoch(Quantity(rowTime, "s"));
    1885             :     // ---- Always reset the epoch
    1886             :     {
    1887             :         #if defined(SDGRID_PERFS)
    1888      358094 :         StartStop trigger(cResetFrame);
    1889             :         #endif
    1890      179047 :         mFrame_p.resetEpoch(rowEpoch);
    1891             :     }
    1892             :     // ---- Reset antenna position only if antenna changed since we were last called
    1893      179047 :     if (lastAntID_p != rowAntenna1) {
    1894             :         // Debug messages
    1895          15 :         if (lastAntID_p == -1) {
    1896             :             // antenna ID is unset
    1897          15 :             logIO_p << LogIO::DEBUGGING
    1898             :                 << "updating antenna position for conversion: new MS ID " << msId_p
    1899          15 :                 << ", antenna ID " << rowAntenna1 << LogIO::POST;
    1900             :         } else {
    1901           0 :             logIO_p << LogIO::DEBUGGING
    1902             :                 << "updating antenna position for conversion: MS ID " << msId_p
    1903             :                 << ", last antenna ID " << lastAntID_p
    1904           0 :                 << ", new antenna ID " << rowAntenna1 << LogIO::POST;
    1905             :         }
    1906             :         const auto & rowAntenna1Position =
    1907          15 :                   vb.msColumns().antenna().positionMeas()(rowAntenna1);
    1908             :         {
    1909             :             #if defined(SDGRID_PERFS)
    1910          30 :             StartStop trigger(cResetFrame);
    1911             :             #endif
    1912          15 :             mFrame_p.resetPosition(rowAntenna1Position);
    1913             :         }
    1914             :         // Remember antenna id for next call,
    1915             :         // which may be done using a different VisBuffer ...
    1916          15 :         lastAntID_p = rowAntenna1;
    1917             :     }
    1918             : 
    1919             :     // 6. Compute user-specified column direction at data-taking time,
    1920             :     //    in image's direction reference frame
    1921      179047 :     if (havePointings) {
    1922      179047 :         if (mustInterpolate) {
    1923             :             #if defined(SDGRID_PERFS)
    1924        5000 :             cInterpolateDirection.start();
    1925             :             #endif
    1926             :             const auto interpolatedDirection =
    1927       10000 :                 directionMeas(pointingColumns, pointingIndex, rowTime);
    1928             :             #if defined(SDGRID_PERFS)
    1929        5000 :             cInterpolateDirection.stop();
    1930        5000 :             cConvertDirection.start();
    1931             :             #endif
    1932             :             worldPosMeas = haveConvertedColumn ?
    1933             :                   interpolatedDirection
    1934        5000 :                 : (*pointingToImage)(interpolatedDirection);
    1935             :             #if defined(SDGRID_PERFS)
    1936        5000 :             cConvertDirection.stop();
    1937             :             #endif
    1938             : 
    1939             :             // Debug stuff
    1940             :             //Vector<Double> newdirv = newdir.getAngle("rad").getValue();
    1941             :             //cerr<<"dir0="<<newdirv(0)<<endl;
    1942             : 
    1943             :             //fprintf(pfile,"%.8f %.8f \n", newdirv(0), newdirv(1));
    1944             :             //printf("%lf %lf \n", newdirv(0), newdirv(1));
    1945             :         } else {
    1946      348094 :             const auto columnDirection = directionMeas(pointingColumns, pointingIndex);
    1947             :             worldPosMeas = haveConvertedColumn ?
    1948             :                     columnDirection
    1949      174047 :                   : (*pointingToImage)(columnDirection);
    1950             :         }
    1951             :     } else {
    1952             :         // Without pointings, this converts the direction of the phase center
    1953           0 :         worldPosMeas = (*pointingToImage)(vb.direction1()(row));
    1954             :     }
    1955             : 
    1956             :     // 7. Convert world position coordinates to image pixel coordinates
    1957             :     {
    1958             :         #if defined(SDGRID_PERFS)
    1959      179047 :         StartStop trigger(cComputeDirectionPixel);
    1960             :         #endif
    1961             : 
    1962      179047 :         rowPixel.isValid = directionCoord.toPixel(xyPos, worldPosMeas);
    1963             :     }
    1964             : 
    1965      179047 :     if (not rowPixel.isValid) {
    1966           0 :         logIO_p << "Failed to find a pixel for pointing direction of "
    1967           0 :             << MVTime(worldPosMeas.getValue().getLong("rad")).string(MVTime::TIME)
    1968           0 :             << ", " << MVAngle(worldPosMeas.getValue().getLat("rad")).string(MVAngle::ANGLE)
    1969           0 :             << LogIO::WARN << LogIO::POST;
    1970           0 :         return rowPixel.isValid;
    1971             :     }
    1972             : 
    1973             :     // 8. Handle moving sources
    1974      179047 :     if (fixMovingSource_p) {
    1975             :         #if defined(SDGRID_PERFS)
    1976       19272 :         StartStop trigger(cHandleMovingSource);
    1977             :         #endif
    1978        9636 :         if (xyPosMovingOrig_p.nelements() < 2) {
    1979           1 :             directionCoord.toPixel(xyPosMovingOrig_p, firstMovingDir_p);
    1980             :         }
    1981             :         //via HADEC or AZEL for parallax of near sources
    1982       19272 :         MDirection::Ref outref1(MDirection::AZEL, mFrame_p);
    1983       19272 :         MDirection tmphadec = MDirection::Convert(movingDir_p, outref1)();
    1984       19272 :         MDirection actSourceDir = (*pointingToImage)(tmphadec);
    1985        9636 :         Vector<Double> actPix;
    1986        9636 :         directionCoord.toPixel(actPix, actSourceDir);
    1987             : 
    1988             :         //cout << row << " scan " << vb.scan()(row) << "xyPos " << xyPos
    1989             :         //     << " xyposmovorig " << xyPosMovingOrig_p << " actPix " << actPix << endl;
    1990             : 
    1991        9636 :         xyPos = xyPos + xyPosMovingOrig_p - actPix;
    1992             :     }
    1993             : 
    1994      179047 :     return rowPixel.isValid;
    1995             : }
    1996             : 
    1997      174260 : MDirection SDGrid::directionMeas(const MSPointingColumns& mspc, const Int& index){
    1998      174260 :   if (pointingDirCol_p == "TARGET") {
    1999           0 :     return mspc.targetMeas(index);
    2000      174260 :   } else if (pointingDirCol_p == "POINTING_OFFSET") {
    2001           0 :     if (!mspc.pointingOffsetMeasCol().isNull()) {
    2002           0 :       return mspc.pointingOffsetMeas(index);
    2003             :     }
    2004           0 :     cerr << "No PONTING_OFFSET column in POINTING table" << endl;
    2005      174260 :   } else if (pointingDirCol_p == "SOURCE_OFFSET") {
    2006           0 :     if (!mspc.sourceOffsetMeasCol().isNull()) {
    2007           0 :       return mspc.sourceOffsetMeas(index);
    2008             :     }
    2009           0 :     cerr << "No SOURCE_OFFSET column in POINTING table" << endl;
    2010      174260 :   } else if (pointingDirCol_p == "ENCODER") {
    2011           0 :     if (!mspc.encoderMeas().isNull()) {
    2012           0 :       return mspc.encoderMeas()(index);
    2013             :     }
    2014           0 :     cerr << "No ENCODER column in POINTING table" << endl;
    2015             :   }
    2016             : 
    2017             :   //default  return this
    2018      174260 :   return mspc.directionMeas(index);
    2019             :   }
    2020             : 
    2021             : // for the cases, interpolation of the pointing direction requires
    2022             : // when data sampling rate higher than the pointing data recording
    2023             : // (e.g. fast OTF)
    2024        5003 : MDirection SDGrid::directionMeas(const MSPointingColumns& mspc, const Int& index,
    2025             :                                  const Double& time){
    2026             :   //spline interpolation
    2027        5003 :   if (isSplineInterpolationReady) {
    2028        5003 :     Int antid = mspc.antennaId()(index);
    2029        5003 :     if (interpolator->doSplineInterpolation(antid)) {
    2030        5003 :       return interpolator->interpolateDirectionMeasSpline(mspc, time, index, antid);
    2031             :     }
    2032             :   }
    2033             : 
    2034             :   //linear interpolation (as done before CAS-7911)
    2035             :   Int index1, index2;
    2036           0 :   if (time < mspc.time()(index)) {
    2037           0 :     if (index > 0) {
    2038           0 :       index1 = index-1;
    2039           0 :       index2 = index;
    2040           0 :     } else if (index == 0) {
    2041           0 :       index1 = index;
    2042           0 :       index2 = index+1;
    2043             :     }
    2044             :   } else {
    2045           0 :     if (index < Int(mspc.nrow()-1)) {
    2046           0 :       index1 = index;
    2047           0 :       index2 = index+1;
    2048           0 :     } else if (index == Int(mspc.nrow()-1) || (mspc.time()(index)-mspc.time()(index+1))>2*mspc.interval()(index)) {
    2049           0 :       index1 = index-1;
    2050           0 :       index2 = index;
    2051             :     }
    2052             :   }
    2053           0 :   return interpolateDirectionMeas(mspc, time, index, index1, index2);
    2054             : }
    2055             : 
    2056           0 : MDirection SDGrid::interpolateDirectionMeas(const MSPointingColumns& mspc,
    2057             :                                             const Double& time,
    2058             :                                             const Int& index,
    2059             :                                             const Int& indx1,
    2060             :                                             const Int& indx2){
    2061           0 :   Vector<Double> dir1,dir2;
    2062           0 :   Vector<Double> newdir(2),scanRate(2);
    2063             :   Double dLon, dLat;
    2064             :   Double ftime,ftime2,ftime1,dtime;
    2065           0 :   MDirection newDirMeas;
    2066           0 :   MDirection::Ref rf;
    2067             :   Bool isfirstRefPt;
    2068             : 
    2069           0 :   if (indx1 == index) {
    2070           0 :     isfirstRefPt = true;
    2071             :   } else {
    2072           0 :     isfirstRefPt = false;
    2073             :   }
    2074             : 
    2075           0 :   if (pointingDirCol_p == "TARGET") {
    2076           0 :     dir1 = mspc.targetMeas(indx1).getAngle("rad").getValue();
    2077           0 :     dir2 = mspc.targetMeas(indx2).getAngle("rad").getValue();
    2078           0 :   } else if (pointingDirCol_p == "POINTING_OFFSET") {
    2079           0 :     if (!mspc.pointingOffsetMeasCol().isNull()) {
    2080           0 :       dir1 = mspc.pointingOffsetMeas(indx1).getAngle("rad").getValue();
    2081           0 :       dir2 = mspc.pointingOffsetMeas(indx2).getAngle("rad").getValue();
    2082             :     } else {
    2083           0 :       cerr << "No PONTING_OFFSET column in POINTING table" << endl;
    2084             :     }
    2085           0 :   } else if (pointingDirCol_p == "SOURCE_OFFSET") {
    2086           0 :     if (!mspc.sourceOffsetMeasCol().isNull()) {
    2087           0 :       dir1 = mspc.sourceOffsetMeas(indx1).getAngle("rad").getValue();
    2088           0 :       dir2 = mspc.sourceOffsetMeas(indx2).getAngle("rad").getValue();
    2089             :     } else {
    2090           0 :       cerr << "No SOURCE_OFFSET column in POINTING table" << endl;
    2091             :     }
    2092           0 :   } else if (pointingDirCol_p == "ENCODER") {
    2093           0 :     if (!mspc.encoderMeas().isNull()) {
    2094           0 :       dir1 = mspc.encoderMeas()(indx1).getAngle("rad").getValue();
    2095           0 :       dir2 = mspc.encoderMeas()(indx2).getAngle("rad").getValue();
    2096             :     } else {
    2097           0 :       cerr << "No ENCODER column in POINTING table" << endl;
    2098             :     }
    2099             :   } else {
    2100           0 :     dir1 = mspc.directionMeas(indx1).getAngle("rad").getValue();
    2101           0 :     dir2 = mspc.directionMeas(indx2).getAngle("rad").getValue();
    2102             :   }
    2103             : 
    2104           0 :   dLon = dir2(0) - dir1(0);
    2105           0 :   dLat = dir2(1) - dir1(1);
    2106           0 :   ftime = floor(mspc.time()(indx1));
    2107           0 :   ftime2 = mspc.time()(indx2) - ftime;
    2108           0 :   ftime1 = mspc.time()(indx1) - ftime;
    2109           0 :   dtime = ftime2 - ftime1;
    2110           0 :   scanRate(0) = dLon/dtime;
    2111           0 :   scanRate(1) = dLat/dtime;
    2112             :   //scanRate(0) = dir2(0)/dtime-dir1(0)/dtime;
    2113             :   //scanRate(1) = dir2(1)/dtime-dir1(1)/dtime;
    2114             :   //Double delT = mspc.time()(index)-time;
    2115             :   //cerr<<"index="<<index<<" dLat="<<dLat<<" dtime="<<dtime<<" delT="<< delT<<endl;
    2116             :   //cerr<<"deldirlat="<<scanRate(1)*fabs(delT)<<endl;
    2117           0 :   if (isfirstRefPt) {
    2118           0 :     newdir(0) = dir1(0)+scanRate(0)*fabs(mspc.time()(index)-time);
    2119           0 :     newdir(1) = dir1(1)+scanRate(1)*fabs(mspc.time()(index)-time);
    2120           0 :     rf = mspc.directionMeas(indx1).getRef();
    2121             :   } else {
    2122           0 :     newdir(0) = dir2(0)-scanRate(0)*fabs(mspc.time()(index)-time);
    2123           0 :     newdir(1) = dir2(1)-scanRate(1)*fabs(mspc.time()(index)-time);
    2124           0 :     rf = mspc.directionMeas(indx2).getRef();
    2125             :   }
    2126             :   //default  return this
    2127           0 :   Quantity rDirLon(newdir(0), "rad");
    2128           0 :   Quantity rDirLat(newdir(1), "rad");
    2129           0 :   newDirMeas = MDirection(rDirLon, rDirLat, rf);
    2130             :   //cerr<<"newDirMeas rf="<<newDirMeas.getRefString()<<endl;
    2131             :   //return mspc.directionMeas(index);
    2132           0 :   return newDirMeas;
    2133             : }
    2134             : 
    2135        4322 : void SDGrid::pickWeights(const VisBuffer& vb, Matrix<Float>& weight){
    2136             :   #if defined(SDGRID_PERFS)
    2137        8644 :   StartStop trigger(cPickWeights);
    2138             :   #endif
    2139             :   //break reference
    2140        4322 :   weight.resize();
    2141             : 
    2142        4322 :   if (useImagingWeight_p) {
    2143           0 :     weight.reference(vb.imagingWeight());
    2144             :   } else {
    2145        8644 :     const Cube<Float> weightspec(vb.weightSpectrum());
    2146        4322 :     weight.resize(vb.nChannel(), vb.nRow());
    2147             : 
    2148        4322 :     if (weightspec.nelements() == 0) {
    2149      356400 :       for (Int k = 0; k < vb.nRow(); ++k) {
    2150             :         //cerr << "nrow " << vb.nRow() << " " << weight.shape() << "  "  << weight.column(k).shape() << endl;
    2151      352078 :         weight.column(k).set(vb.weight()(k));
    2152             :       }
    2153             :     } else {
    2154           0 :       Int npol = weightspec.shape()(0);
    2155           0 :       if (npol == 1) {
    2156           0 :         for (Int k = 0; k < vb.nRow(); ++k) {
    2157           0 :           for (int chan = 0; chan < vb.nChannel(); ++chan) {
    2158           0 :             weight(chan, k)=weightspec(0, chan, k);
    2159             :           }
    2160             :         }
    2161             :       } else {
    2162           0 :         for (Int k = 0; k < vb.nRow(); ++k) {
    2163           0 :           for (int chan = 0; chan < vb.nChannel(); ++chan) {
    2164           0 :             weight(chan, k) = (weightspec(0, chan, k) + weightspec((npol-1), chan, k))/2.0f;
    2165             :           }
    2166             :         }
    2167             :       }
    2168             :     }
    2169             :   }
    2170        4322 : }
    2171             : 
    2172         228 : void SDGrid::clipMinMax() {
    2173         228 :   if (clipminmax_) {
    2174             :     Bool gmin_b, gmax_b, wmin_b, wmax_b, np_b;
    2175          16 :     const auto *gmin_p = gmin_.getStorage(gmin_b);
    2176          16 :     const auto *gmax_p = gmax_.getStorage(gmax_b);
    2177          16 :     const auto *wmin_p = wmin_.getStorage(wmin_b);
    2178          16 :     const auto *wmax_p = wmax_.getStorage(wmax_b);
    2179          16 :     const auto *np_p = npoints_.getStorage(np_b);
    2180             : 
    2181             :     Bool data_b, weight_b, sumw_b;
    2182          16 :     auto data_p = griddedData.getStorage(data_b);
    2183          16 :     auto weight_p = wGriddedData.getStorage(weight_b);
    2184          16 :     auto sumw_p = sumWeight.getStorage(sumw_b);
    2185             : 
    2186          32 :     auto arrayShape = griddedData.shape();
    2187          16 :     size_t num_xy = arrayShape.getFirst(2).product();
    2188          16 :     size_t num_polchan = arrayShape.getLast(2).product();
    2189         160 :     for (size_t i = 0; i < num_xy; ++i) {
    2190         306 :       for (size_t j = 0; j < num_polchan; ++j) {
    2191         162 :         auto k = i * num_polchan + j;
    2192         162 :         if (np_p[k] == 1) {
    2193           2 :           auto wt = wmin_p[k];
    2194           2 :           data_p[k] = wt * gmin_p[k];
    2195           2 :           weight_p[k] = wt;
    2196           2 :           sumw_p[j] += wt;
    2197         160 :         } else if (np_p[k] == 2) {
    2198           1 :           auto wt = wmin_p[k];
    2199           1 :           data_p[k] = wt * gmin_p[k];
    2200           1 :           weight_p[k] = wt;
    2201           1 :           sumw_p[j] += wt;
    2202           1 :           wt = wmax_p[k];
    2203           1 :           data_p[k] += wt * gmax_p[k];
    2204           1 :           weight_p[k] += wt;
    2205           1 :           sumw_p[j] += wt;
    2206             :         }
    2207             :       }
    2208             :     }
    2209             : 
    2210          16 :     wGriddedData.putStorage(weight_p, weight_b);
    2211          16 :     griddedData.putStorage(data_p, data_b);
    2212          16 :     sumWeight.putStorage(sumw_p, sumw_b);
    2213             : 
    2214          16 :     npoints_.freeStorage(np_p, np_b);
    2215          16 :     wmax_.freeStorage(wmax_p, wmax_b);
    2216          16 :     wmin_.freeStorage(wmin_p, wmin_b);
    2217          16 :     gmax_.freeStorage(gmax_p, gmax_b);
    2218          16 :     gmin_.freeStorage(gmin_p, gmin_b);
    2219             :   }
    2220         228 : }
    2221             : 
    2222         124 : SDGrid::MaskedPixelRef::MaskedPixelRef(Vector<Double>& xyIn, Bool isValidIn)
    2223             :   : xy {xyIn},
    2224         124 :     isValid {isValidIn}
    2225         124 : {}
    2226             : 
    2227             : SDGrid::MaskedPixelRef&
    2228           0 : SDGrid::MaskedPixelRef::operator=(const SDGrid::MaskedPixelRef &other) {
    2229           0 :   xy = other.xy;
    2230           0 :   isValid = other.isValid;
    2231           0 :   return *this;
    2232             : }
    2233             : 
    2234      176039 : SDGrid::MaskedPixel::MaskedPixel(Double xIn, Double yIn, Bool isValidIn)
    2235             :     : x {xIn},
    2236             :       y {yIn},
    2237      176039 :       isValid {isValidIn}
    2238      176039 : {}
    2239             : 
    2240         124 : SDGrid::Cache::Cache(SDGrid &parent)
    2241             :     : sdgrid {parent},
    2242             :       isOpened {false},
    2243             :       accessMode {AccessMode::READ},
    2244             :       canRead {false},
    2245             :       canWrite {false},
    2246         124 :       inputPixel {sdgrid.rowPixel},
    2247         124 :       outputPixel {sdgrid.rowPixel}
    2248         124 : {}
    2249             : 
    2250         258 : const casacore::String& SDGrid::Cache::className() {
    2251         258 :     static casacore::String className_ = "SDGrid::Cache";
    2252         258 :     return className_;
    2253             : }
    2254             : 
    2255           0 :  SDGrid::Cache& SDGrid::Cache::operator=(const Cache &other) {
    2256           0 :     sdgrid = other.sdgrid;
    2257           0 :     msCaches = other.msCaches;
    2258           0 :     isOpened = false;
    2259           0 :     canRead = false;
    2260           0 :     canWrite = false;
    2261             :     // inputPixel = sdgrid.rowPixel;
    2262           0 :     inputPixel.xy = sdgrid.rowPixel.xy;
    2263             :     //inputPixel.isValid = sdgrid.rowPixel.isValid;
    2264             :     // <=>
    2265           0 :     msPixels = nullptr;
    2266           0 :     outputPixel = other.outputPixel;
    2267           0 :     msCacheReadIterator =  MsCaches::const_iterator();
    2268           0 :     pixelReadIterator = Pixels::const_iterator();
    2269           0 :     return *this;
    2270             :  }
    2271             : 
    2272             : void
    2273         228 : SDGrid::Cache::open(AccessMode accessModeIn) {
    2274         228 :     if (isOpened) {
    2275           0 :       LogIO logger(LogOrigin(className(), "open", WHERE));
    2276           0 :       logger << "BUG: Opened " << className() << " was re-opened before being closed." << LogIO::EXCEPTION;
    2277             :     }
    2278         228 :     isOpened = true;
    2279         228 :     accessMode = accessModeIn;
    2280         228 :     canRead = accessMode == AccessMode::READ;
    2281         228 :     canWrite = accessMode == AccessMode::WRITE;
    2282         228 :     if (outputPixel.xy.size() < 2) {
    2283         114 :       outputPixel.xy.resize(2);
    2284         114 :       outputPixel.isValid = false;
    2285             :     }
    2286         228 :     rewind();
    2287         228 : }
    2288             : 
    2289             : void
    2290         228 : SDGrid::Cache::rewind() {
    2291             :     // Writer
    2292         228 :     msPixels = nullptr;
    2293             : 
    2294             :     // Reader
    2295         228 :     msCacheReadIterator = msCaches.cbegin();
    2296         228 :     pixelReadIterator = Pixels::const_iterator();
    2297         228 : }
    2298             : 
    2299             : void
    2300         228 : SDGrid::Cache::close() {
    2301         228 :     if (not isOpened) {
    2302           0 :       LogIO logger(LogOrigin(className(), "close", WHERE));
    2303           0 :       logger << "BUG: Closed " << className() << " was re-closed before being opened." << LogIO::EXCEPTION;
    2304             :     }
    2305         228 :     if (isWriteable()) {
    2306             :         // Make sure we have 1 pixel per row
    2307         243 :         for (const auto & msCache : msCaches) {
    2308         129 :             if (not msCache.isConsistent()) {
    2309           0 :                 LogIO logger(LogOrigin(className(), "close", WHERE));
    2310           0 :                 const auto didOverflow = msCache.pixels.size() > msCache.nRows;
    2311           0 :                 const auto overOrUnder = didOverflow ? "over" : "under";
    2312             :                 logger << "BUG: Cache " << overOrUnder << "flow:"
    2313           0 :                        << " nRows=" << msCache.nRows
    2314             :                        << " != nPixels=" <<  msCache.pixels.size()
    2315           0 :                        << " for: " << msCache.msPath
    2316           0 :                        << " with selection: " << msCache.msTableName
    2317           0 :                        << LogIO::EXCEPTION;
    2318             :             }
    2319             :         }
    2320             :     }
    2321             :     // Reset state
    2322         228 :     isOpened = false;
    2323         228 :     accessMode = AccessMode::READ;
    2324         228 :     canRead = false;
    2325         228 :     canWrite = false;
    2326         228 : }
    2327             : 
    2328             : Bool
    2329      352465 : SDGrid::Cache::isReadable() const {
    2330      352465 :     return isOpened and canRead;
    2331             : }
    2332             : 
    2333             : Bool
    2334      176525 : SDGrid::Cache::isWriteable() const {
    2335      176525 :     return isOpened and canWrite;
    2336             : }
    2337             : 
    2338             : Bool
    2339         228 : SDGrid::Cache::isEmpty() const {
    2340         228 :     return msCaches.empty();
    2341             : }
    2342             : 
    2343             : void
    2344           0 : SDGrid::Cache::clear()  {
    2345           0 :     msCaches.clear();
    2346           0 : }
    2347             : 
    2348         129 : SDGrid::Cache::MsCache::MsCache(const String& msPathIn, const String& msTableNameIn, rownr_t nRowsIn)
    2349             :     : msPath {msPathIn},
    2350             :       msTableName {msTableNameIn},
    2351         129 :       nRows {nRowsIn}
    2352             : {
    2353         129 :     pixels.reserve(nRows);
    2354         129 : }
    2355             : 
    2356         129 : Bool SDGrid::Cache::MsCache::isConsistent() const {
    2357         129 :   return pixels.size() == nRows;
    2358             : }
    2359             : 
    2360             : void
    2361         258 : SDGrid::Cache::newMS(const MeasurementSet& ms) {
    2362         516 :     LogIO os(LogOrigin(className(),"newMS"));
    2363         258 :     const auto msPath =  ms.getPartNames()[0];
    2364             : 
    2365         258 :     if (isWriteable()) {
    2366         129 :         os << "Will compute and cache spectra pixels coordinates for: " << msPath << LogIO::POST;
    2367         129 :         msCaches.emplace_back(msPath, ms.tableName(), ms.nrow());
    2368         129 :         msPixels = &(msCaches.back().pixels);
    2369         129 :         return;
    2370             :     }
    2371             : 
    2372         129 :     if (isReadable()) {
    2373         129 :         os << "Will load cached spectra pixels coordinates for: " << msPath << LogIO::POST;
    2374         129 :         if (msCacheReadIterator == msCaches.cend()) {
    2375           0 :             os << "BUG! Cached data missing for: " << msPath << LogIO::EXCEPTION;
    2376             :         }
    2377         129 :         const auto & pixelsToLoad = msCacheReadIterator->pixels;
    2378         129 :         if (pixelsToLoad.size() != ms.nrow()) {
    2379             :             os << "BUG! Cached data size mismatch for: " << msPath
    2380             :                << " : nRows: " << ms.nrow()
    2381           0 :                << " nCachedRows: " << pixelsToLoad.size() << LogIO::EXCEPTION;
    2382             :         }
    2383         129 :         if (  msCacheReadIterator->msTableName != ms.tableName()) {
    2384             :             os << "BUG! Cached data was probably for a different selection of: " << msPath
    2385             :                << " current selection: " << ms.tableName()
    2386           0 :                << " cached selection: " <<  msCacheReadIterator->msTableName << LogIO::EXCEPTION;
    2387             :         }
    2388         129 :         pixelReadIterator = pixelsToLoad.cbegin();
    2389         129 :         ++msCacheReadIterator;
    2390             :     }
    2391             : }
    2392             : 
    2393             : void
    2394      176039 : SDGrid::Cache::storeRowPixel() {
    2395      176039 :     msPixels->emplace_back(
    2396      176039 :         inputPixel.xy[0],
    2397      176039 :         inputPixel.xy[1],
    2398      176039 :         inputPixel.isValid
    2399             :     );
    2400      176039 : }
    2401             : 
    2402             : void
    2403      176039 : SDGrid::Cache::loadRowPixel() {
    2404      176039 :     const auto & pixel = *pixelReadIterator;
    2405      176039 :     outputPixel.xy[0] = pixel.x;
    2406      176039 :     outputPixel.xy[1] = pixel.y;
    2407      176039 :     outputPixel.isValid = pixel.isValid;
    2408      176039 :     ++pixelReadIterator;
    2409      176039 : }
    2410             : 
    2411         228 : SDGrid::CacheManager::CacheManager(Cache& cacheIn,
    2412         228 :     Bool onDutyIn,  Cache::AccessMode accessModeIn)
    2413             :     : cache {cacheIn},
    2414             :       onDuty {onDutyIn},
    2415         228 :       accessMode {accessModeIn}
    2416             : {
    2417         228 :     if (onDuty) {
    2418         228 :       cache.open(accessMode);
    2419             :     }
    2420         228 : }
    2421             : 
    2422         456 : SDGrid::CacheManager::~CacheManager()
    2423             : {
    2424         228 :     if (onDuty) {
    2425         228 :       cache.close();
    2426             :     }
    2427         228 : }
    2428             : 
    2429      179047 : SDGrid::CacheWriter::CacheWriter(Cache& cacheIn,
    2430      179047 :     Bool onDutyIn)
    2431             :     : cache {cacheIn},
    2432      179047 :       onDuty {onDutyIn}
    2433      179047 : {}
    2434             : 
    2435      358094 : SDGrid::CacheWriter::~CacheWriter()
    2436             : {
    2437      179047 :     if (onDuty) {
    2438      176039 :       cache.storeRowPixel();
    2439             :     }
    2440      179047 : }
    2441             : 
    2442         114 : const String & SDGrid::toString(const ConvertFirst convertFirst) {
    2443             :     static const std::array<String,3> name {
    2444             :         "NEVER",
    2445             :         "ALWAYS",
    2446             :         "AUTO"
    2447         114 :     };
    2448         114 :     switch(convertFirst){
    2449         114 :     case ConvertFirst::NEVER:
    2450             :     case ConvertFirst::ALWAYS:
    2451             :     case ConvertFirst::AUTO:
    2452         114 :         return name[static_cast<size_t>(convertFirst)];
    2453           0 :     default:
    2454           0 :         String errMsg {"Illegal ConvertFirst enum: "};
    2455           0 :         errMsg += String::toString(static_cast<Int>(convertFirst));
    2456             :         throw AipsError(
    2457             :             errMsg,
    2458             :             __FILE__,
    2459             :             __LINE__,
    2460             :             AipsError::Category::INVALID_ARGUMENT
    2461           0 :         );
    2462             :         // Avoid potential compiler warning
    2463             :         return name[static_cast<size_t>(ConvertFirst::NEVER)];
    2464             :     }
    2465             : }
    2466             : 
    2467         114 : SDGrid::ConvertFirst SDGrid::fromString(const String & name) {
    2468             :     static const std::array<ConvertFirst,3> schemes {
    2469             :         ConvertFirst::NEVER,
    2470             :         ConvertFirst::ALWAYS,
    2471             :         ConvertFirst::AUTO
    2472             :     };
    2473         114 :     for ( const auto scheme : schemes ) {
    2474         114 :         if (name == toString(scheme)) return scheme;
    2475             :     }
    2476           0 :     String errMsg {"Illegal ConvertFirst name: "};
    2477           0 :     errMsg += name;
    2478             :     throw AipsError(
    2479             :         errMsg,
    2480             :         __FILE__,
    2481             :         __LINE__,
    2482             :         AipsError::Category::INVALID_ARGUMENT
    2483           0 :     );
    2484             :     // Avoid potential compiler warning
    2485             :     return ConvertFirst::NEVER;
    2486             : }
    2487             : 
    2488         114 :  void SDGrid::setConvertFirst(const casacore::String &name) {
    2489         114 :     processingScheme = fromString(name);
    2490         114 :  }
    2491             : 
    2492         258 : Bool SDGrid::mustConvertPointingColumn(
    2493             :         const MeasurementSet &ms
    2494             :     ) {
    2495             :     const auto haveCachedSpectraPixelCoordinates =
    2496         258 :         cacheIsEnabled and cache.isReadable();
    2497         258 :     if (haveCachedSpectraPixelCoordinates) return False;
    2498             : 
    2499         129 :     switch(processingScheme){
    2500           0 :     case ConvertFirst::ALWAYS: return True;
    2501         129 :     case ConvertFirst::NEVER:  return False;
    2502           0 :     case ConvertFirst::AUTO:
    2503             :         {
    2504           0 :             const auto nPointings = ms.pointing().nrow();
    2505           0 :             const auto nSelectedDataRows = ms.nrow();
    2506           0 :             return nSelectedDataRows > nPointings ? True : False;
    2507             :         }
    2508           0 :     default:
    2509           0 :         String errMsg {"Unexpected invalid state: "};
    2510           0 :         errMsg += "ConvertFirst processingScheme=";
    2511           0 :         errMsg += String::toString<Int>(static_cast<Int>(processingScheme));
    2512           0 :         errMsg += " ms=" + ms.tableName();
    2513             :         throw AipsError(
    2514             :             errMsg,
    2515             :             __FILE__,
    2516             :             __LINE__,
    2517             :             AipsError::Category::GENERAL
    2518           0 :         );
    2519             :     }
    2520             :     // Avoid potential compiler warning
    2521             :     return False;
    2522             : }
    2523             : 
    2524         258 : void SDGrid::handleNewMs(
    2525             :     ROVisibilityIterator &vi,
    2526             :     const ImageInterface<Complex>& image) {
    2527             : 
    2528             :     // Synchronize spatial coordinates cache
    2529         258 :     if (cacheIsEnabled) cache.newMS(vi.ms());
    2530             : 
    2531             :     // Handle interpolate-convert processing scheme
    2532         258 :     if (mustConvertPointingColumn(vi.ms())) {
    2533           0 :         const auto columnEnum = MSPointing::columnType(pointingDirCol_p);
    2534             :         const auto refType =
    2535           0 :             image.coordinates().directionCoordinate().directionType();
    2536           0 :         convertPointingColumn(vi.ms(), columnEnum, refType);
    2537             :     }
    2538             :     else {
    2539         258 :         ramPointingTable = MSPointing();
    2540         258 :         ramPointingColumnsPtr.reset();
    2541             :     }
    2542         258 : }
    2543             : 
    2544             : namespace convert_pointing_column_helpers {
    2545             : using DirectionComputer = std::function<MDirection (rownr_t)>;
    2546             : 
    2547             : DirectionComputer
    2548           0 : metaDirectionComputer(
    2549             :     const MSPointingColumns &pointingColumns,
    2550             :     MSPointing::PredefinedColumns columnEnum) {
    2551             :     using std::placeholders::_1;
    2552             :     using Column = MSPointing::PredefinedColumns;
    2553           0 :     const auto & encoderDirections = pointingColumns.encoderMeas();
    2554           0 :     switch(columnEnum) {
    2555           0 :         case Column::DIRECTION:
    2556           0 :             return std::bind(
    2557           0 :                 &MSPointingColumns::directionMeas,
    2558           0 :                 &pointingColumns,
    2559             :                 _1,
    2560           0 :                 Double {0.0}
    2561           0 :             );
    2562             :             break;
    2563           0 :         case Column::TARGET:
    2564           0 :             return std::bind(
    2565           0 :                 &MSPointingColumns::targetMeas,
    2566           0 :                 &pointingColumns,
    2567             :                 _1,
    2568           0 :                 Double {0.0}
    2569           0 :             );
    2570             :             break;
    2571           0 :         case Column::SOURCE_OFFSET:
    2572           0 :             return std::bind(
    2573           0 :                 &MSPointingColumns::sourceOffsetMeas,
    2574           0 :                 &pointingColumns,
    2575             :                 _1,
    2576           0 :                 Double {0.0}
    2577           0 :             );
    2578             :             break;
    2579           0 :         case Column::POINTING_OFFSET:
    2580           0 :             return std::bind(
    2581           0 :                 &MSPointingColumns::pointingOffsetMeas,
    2582           0 :                 &pointingColumns,
    2583             :                 _1,
    2584           0 :                 Double {0.0}
    2585           0 :             );
    2586             :             break;
    2587           0 :         case Column::ENCODER:
    2588           0 :             return std::bind(
    2589           0 :                 &ScalarMeasColumn<MDirection>::operator(),
    2590           0 :                 &encoderDirections,
    2591             :                 _1
    2592           0 :             );
    2593             :             break;
    2594           0 :         default:
    2595             :             throw AipsError(
    2596           0 :                 String("Illegal Pointing Column Enum: " + String::toString(columnEnum)),
    2597             :                 AipsError::INVALID_ARGUMENT
    2598           0 :             );
    2599             :     }
    2600             : }
    2601             : 
    2602             : // DirectionArchiver
    2603             : class DirectionArchiver {
    2604             : public:
    2605             :     virtual void put(rownr_t row, const MDirection & dir) = 0;
    2606             : };
    2607             : 
    2608             : // Derived Templated Class,
    2609             : // implementing the shared constructor.
    2610             : template<typename ColumnType, typename CellType>
    2611             : class DirectionArchiver_ : public DirectionArchiver {
    2612             : public:
    2613           0 :     DirectionArchiver_(ColumnType &columnIn)
    2614           0 :         : column {columnIn}
    2615           0 :         {}
    2616             :     void put(rownr_t row, const MDirection & dir);
    2617             : private:
    2618             :     ColumnType & column;
    2619             : };
    2620             : 
    2621             : // Specializations of "put" member
    2622             : template<>
    2623           0 : void DirectionArchiver_<MDirection::ScalarColumn, MDirection>::put(
    2624             :     rownr_t row, const MDirection &dir) {
    2625           0 :     column.put(row, dir);
    2626           0 : }
    2627             : 
    2628             : template<>
    2629           0 : void DirectionArchiver_<MDirection::ArrayColumn, Array<MDirection>>::put(
    2630             :     rownr_t row, const MDirection &dir) {
    2631           0 :     column.put(row, Vector<MDirection> {dir});
    2632           0 : }
    2633             : 
    2634             : // Template instantiations for the types we are interested in.
    2635             : template class DirectionArchiver_ <MDirection::ArrayColumn, Array<MDirection>>;
    2636             : template class DirectionArchiver_ <MDirection::ScalarColumn, MDirection>;
    2637             : 
    2638             : // Aliases
    2639             : using ScalarArchiver =
    2640             :         DirectionArchiver_ <MDirection::ScalarColumn, MDirection>;
    2641             : using ArrayArchiver =
    2642             :         DirectionArchiver_ <MDirection::ArrayColumn, Array<MDirection>>;
    2643             : 
    2644             : 
    2645             : struct ArchiverFactory {
    2646             :     static DirectionArchiver * createArchiver(
    2647             :         TableMeasColumn & column
    2648             :     );
    2649             : };
    2650             : 
    2651             : DirectionArchiver *
    2652           0 : ArchiverFactory::createArchiver(TableMeasColumn &column) {
    2653             :         try {
    2654           0 :             auto & scalarColumn = dynamic_cast<MDirection::ScalarColumn &>(column);
    2655           0 :             return new ScalarArchiver(scalarColumn);
    2656             :         }
    2657           0 :         catch(std::bad_cast & exception) {
    2658           0 :             auto & arrayColumn = dynamic_cast<MDirection::ArrayColumn &>(column);
    2659           0 :             return  new ArrayArchiver(arrayColumn);
    2660             :         }
    2661             : }
    2662             : 
    2663             : TableMeasColumn &
    2664           0 : columnData(
    2665             :     MSPointingColumns & pointingColumns,
    2666             :     MSPointing::PredefinedColumns columnEnum) {
    2667             :     using Column = MSPointing::PredefinedColumns;
    2668           0 :     switch(columnEnum){
    2669             :         // Array Columns
    2670           0 :         case Column::DIRECTION:
    2671           0 :             return pointingColumns.directionMeasCol();
    2672           0 :         case Column::TARGET:
    2673           0 :             return pointingColumns.targetMeasCol();
    2674           0 :         case Column::SOURCE_OFFSET:
    2675           0 :             return pointingColumns.sourceOffsetMeasCol();
    2676           0 :         case Column::POINTING_OFFSET:
    2677           0 :             return pointingColumns.pointingOffsetMeasCol();
    2678             :         // Scalar Column
    2679           0 :         case Column::ENCODER:
    2680           0 :             return pointingColumns.encoderMeas();
    2681           0 :         default:
    2682             :             {
    2683           0 :                 LogIO logger {LogOrigin {"columnData"} };
    2684             :                 logger << LogIO::EXCEPTION
    2685             :                     << "Expected a column of directions, got: " << MSPointing::columnName(columnEnum)
    2686           0 :                     << LogIO::POST;
    2687             : 
    2688             :                 // This is just to silence the following compiler warning:
    2689             :                 // warning: control reaches end of non-void function [-Wreturn-type]
    2690           0 :                 return pointingColumns.directionMeasCol();
    2691             :             }
    2692             :     }
    2693             : }
    2694             : 
    2695             : } // namespace convert_pointing_column_helpers
    2696             : using namespace convert_pointing_column_helpers;
    2697             : 
    2698           0 : void SDGrid::convertPointingColumn(
    2699             :     const MeasurementSet & ms,
    2700             :     const MSPointingEnums::PredefinedColumns columnEnum,
    2701             :     const MDirection::Types refType) {
    2702             : 
    2703           0 :     LogIO logger {LogOrigin {"SDGrid", "convertPointingColumn"}};
    2704           0 :     logger << "Start" << LogIO::POST;
    2705             : 
    2706           0 :     initRamPointingTable(ms.pointing(), columnEnum, refType);
    2707             : 
    2708             :     // Setup helper tools
    2709             :     // ---- Conversion Tools
    2710           0 :     MeasFrame pointingMeasurements;
    2711           0 :     MDirection::Convert convertToImageDirectionRef;
    2712           0 :     std::tie(
    2713             :         pointingMeasurements,
    2714             :         convertToImageDirectionRef
    2715           0 :     ) = setupConversionTools(ms, refType);
    2716             : 
    2717             :     // ---- Direction Computer
    2718           0 :     MSPointingColumns pointingColumns {ms.pointing()};
    2719             :     auto userSpecifiedDirection =
    2720           0 :          metaDirectionComputer(pointingColumns, columnEnum);
    2721             : 
    2722             :    // ---- Direction Archiver
    2723           0 :     MSPointingColumns ramPointingColumns {ramPointingTable};
    2724             :     std::unique_ptr<DirectionArchiver> correspondingRamPointingColumn {
    2725             :         ArchiverFactory::createArchiver(
    2726             :             columnData(
    2727             :                 ramPointingColumns,
    2728             :                 columnEnum
    2729             :             )
    2730             :         )
    2731           0 :     };
    2732             : 
    2733             :     // Convert directions stored in user-specified
    2734             :     // POINTING column (of some direction),
    2735             :     // and store the result into the corresponding column
    2736             :     // of the RAM POINTING table
    2737           0 :     const auto & epoch =  pointingColumns.timeMeas();
    2738           0 :     const auto & antennaId = pointingColumns.antennaId();
    2739             : 
    2740           0 :     MSAntennaColumns antennaColumns(ms.antenna());
    2741           0 :     const auto & antennaPosition  = antennaColumns.positionMeas();
    2742             : 
    2743             :     // Main loop control
    2744           0 :     const auto pointingRows = ms.pointing().nrow();
    2745           0 :     constexpr Int invalidAntennaId = -1;
    2746           0 :     auto previousPointing_AntennaId {invalidAntennaId};
    2747             : 
    2748             :     // Main loop
    2749           0 :     for (rownr_t pointingRow = 0; pointingRow < pointingRows ; ++pointingRow){
    2750             :         // Collect pointing measurements
    2751           0 :         const auto pointing_Epoch = epoch(pointingRow);
    2752           0 :         pointingMeasurements.resetEpoch(pointing_Epoch);
    2753             : 
    2754           0 :         const auto pointing_AntennaId = antennaId(pointingRow);
    2755           0 :         const auto antennaChanged =
    2756             :             ( pointing_AntennaId != previousPointing_AntennaId );
    2757           0 :         if (antennaChanged) {
    2758             :             const auto new_AntennaPosition =
    2759           0 :                 antennaPosition(pointing_AntennaId);
    2760           0 :             pointingMeasurements.resetPosition(new_AntennaPosition);
    2761           0 :             previousPointing_AntennaId = pointing_AntennaId;
    2762             :         }
    2763             : 
    2764             :         // Convert
    2765             :         const auto convertedDirection =
    2766             :             convertToImageDirectionRef(
    2767           0 :                 userSpecifiedDirection(pointingRow)
    2768           0 :             );
    2769             : 
    2770             :         // Store
    2771           0 :         correspondingRamPointingColumn->put(
    2772             :              pointingRow,
    2773             :              convertedDirection
    2774           0 :         );
    2775             :     }
    2776             : 
    2777           0 :     logger << "Done" << LogIO::POST;
    2778           0 : }
    2779             : 
    2780           0 : void SDGrid::initRamPointingTable(
    2781             :     const MSPointing & pointingTable,
    2782             :     const MSPointingEnums::PredefinedColumns columnEnum,
    2783             :     const MDirection::Types refType) {
    2784             : 
    2785           0 :     LogIO logger {LogOrigin {"SDGrid", "initRamPointingTable"}};
    2786           0 :     logger << "Start" << LogIO::POST;
    2787             : 
    2788           0 :     constexpr auto doNotCopyRows = True;
    2789           0 :     ramPointingTable = pointingTable.copyToMemoryTable(
    2790           0 :         pointingTable.tableName() +
    2791           0 :         "." + MSPointing::columnName(columnEnum) +
    2792           0 :         "." + MDirection::showType(refType),
    2793             :         doNotCopyRows
    2794           0 :     );
    2795           0 :     ramPointingColumnsPtr.reset( new MSPointingColumns {ramPointingTable});
    2796             : 
    2797           0 :     MSPointingColumns pointingColumns {pointingTable};
    2798             : 
    2799           0 :     ramPointingColumnsPtr->setDirectionRef(refType);
    2800           0 :     ramPointingColumnsPtr->setEncoderDirectionRef(refType);
    2801             : 
    2802           0 :     ramPointingTable.addRow(pointingTable.nrow());
    2803             : 
    2804           0 :     ramPointingColumnsPtr->antennaId().putColumn(pointingColumns.antennaId());
    2805           0 :     ramPointingColumnsPtr->time().putColumn(pointingColumns.time());
    2806           0 :     ramPointingColumnsPtr->interval().putColumn(pointingColumns.interval());
    2807           0 :     ramPointingColumnsPtr->numPoly().fillColumn(0);
    2808             : 
    2809           0 :     logger << "Done" << LogIO::POST;
    2810           0 : }
    2811             : 
    2812             : std::pair<MeasFrame,MDirection::Convert>
    2813           0 : SDGrid::setupConversionTools(
    2814             :     const MeasurementSet & ms,
    2815             :     const casacore::MDirection::Types refType) {
    2816             : 
    2817           0 :     LogIO logger {LogOrigin {"SDGrid", "setupConversionTools"}};
    2818           0 :     logger << "Start" << LogIO::POST;
    2819             : 
    2820           0 :     MSPointingColumns pointingColumns(ms.pointing());
    2821           0 :     MSAntennaColumns antennaColumns(ms.antenna());
    2822             : 
    2823           0 :     auto firstPointing_Epoch = pointingColumns.timeMeas()(0);
    2824           0 :     auto firstPointing_AntennaId = pointingColumns.antennaId()(0);
    2825           0 :     auto firstPointing_AntennaPosition = antennaColumns.positionMeas()(
    2826             :         static_cast<rownr_t>(firstPointing_AntennaId)
    2827           0 :     );
    2828             : 
    2829           0 :     MeasFrame measFrame(firstPointing_Epoch, firstPointing_AntennaPosition);
    2830             : 
    2831             :     // Direction Conversion Machine
    2832           0 :     MDirection::Ref dstRef(refType, measFrame);
    2833           0 :     auto firstPointing_Direction = pointingColumns.directionMeas(0);
    2834           0 :     MDirection::Convert convert(firstPointing_Direction, dstRef);
    2835             : 
    2836             :     // ---- Perform 1 dummy conversion at a time far before
    2837             :     //      the first pointing time, so that when we will next convert
    2838             :     //      the first user-specified direction,
    2839             :     //      we are sure that values cached in static variables
    2840             :     //      of casacore functions like dUT1() will be cleared
    2841             :     static const MVEpoch oneYear {
    2842           0 :         Quantity {
    2843             :             365,
    2844           0 :             Unit { "d" }
    2845             :         }
    2846           0 :     };
    2847             :     const MEpoch dummy_Epoch {
    2848           0 :         firstPointing_Epoch.getValue() - oneYear,
    2849           0 :         firstPointing_Epoch.getRef()
    2850           0 :     };
    2851           0 :     measFrame.resetEpoch(dummy_Epoch);
    2852           0 :     const auto dummy_Direction = convert();
    2853             : 
    2854           0 :     logger << "Done" << LogIO::POST;
    2855           0 :     return std::make_pair(measFrame, convert);
    2856             : }
    2857             : 
    2858             : } // casa namespace

Generated by: LCOV version 1.16