LCOV - code coverage report
Current view: top level - synthesis/MeasurementComponents - SDGrid.cc (source / functions) Hit Total Coverage
Test: casacpp_coverage.info Lines: 0 1486 0.0 %
Date: 2024-10-29 13:38:20 Functions: 0 96 0.0 %

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

Generated by: LCOV version 1.16