LCOV - code coverage report
Current view: top level - synthesis/TransformMachines2 - FTMachine.cc (source / functions) Hit Total Coverage
Test: casacpp_coverage.info Lines: 364 1656 22.0 %
Date: 2024-10-04 18:58:15 Functions: 20 71 28.2 %

          Line data    Source code
       1             : //# FTMachine.cc: Implementation of FTMachine class
       2             : //# Copyright (C) 1997-2016
       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 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 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             : #include <cmath>
      28             : #include <casacore/casa/Quanta/Quantum.h>
      29             : #include <casacore/casa/Quanta/UnitMap.h>
      30             : #include <casacore/casa/Quanta/UnitVal.h>
      31             : #include <casacore/measures/Measures/Stokes.h>
      32             : #include <casacore/casa/Quanta/Euler.h>
      33             : #include <casacore/casa/Quanta/RotMatrix.h>
      34             : #include <casacore/measures/Measures/MFrequency.h>
      35             : #include <casacore/coordinates/Coordinates/CoordinateSystem.h>
      36             : #include <casacore/coordinates/Coordinates/DirectionCoordinate.h>
      37             : #include <casacore/coordinates/Coordinates/SpectralCoordinate.h>
      38             : #include <casacore/coordinates/Coordinates/StokesCoordinate.h>
      39             : #include <casacore/coordinates/Coordinates/Projection.h>
      40             : #include <casacore/lattices/Lattices/LatticeLocker.h>
      41             : #include <casacore/ms/MeasurementSets/MSColumns.h>
      42             : #include <casacore/casa/BasicSL/Constants.h>
      43             : #include <synthesis/TransformMachines2/FTMachine.h>
      44             : #include <synthesis/TransformMachines2/SkyJones.h>
      45             : #include <synthesis/TransformMachines2/VisModelData.h>
      46             : #include <synthesis/TransformMachines2/BriggsCubeWeightor.h>
      47             : #include <casacore/scimath/Mathematics/RigidVector.h>
      48             : #include <synthesis/TransformMachines/StokesImageUtil.h>
      49             : #include <synthesis/TransformMachines2/Utils.h>
      50             : #include <msvis/MSVis/VisibilityIterator2.h>
      51             : #include <msvis/MSVis/VisBuffer2.h>
      52             : #include <msvis/MSVis/StokesVector.h>
      53             : #include <msvis/MSVis/MSUtil.h>
      54             : #include <casacore/images/Images/ImageInterface.h>
      55             : #include <casacore/images/Images/PagedImage.h>
      56             : #include <casacore/images/Images/ImageUtilities.h>
      57             : #include <casacore/casa/Containers/Block.h>
      58             : #include <casacore/casa/Containers/Record.h>
      59             : #include <casacore/casa/Arrays/ArrayIter.h>
      60             : #include <casacore/casa/Arrays/ArrayLogical.h>
      61             : #include <casacore/casa/Arrays/ArrayMath.h>
      62             : #include <casacore/casa/Arrays/MatrixMath.h>
      63             : #include <casacore/casa/Arrays/MaskedArray.h>
      64             : #include <casacore/casa/Arrays/Array.h>
      65             : #include <casacore/casa/Arrays/Vector.h>
      66             : #include <casacore/casa/Arrays/Matrix.h>
      67             : #include <casacore/casa/Arrays/MatrixIter.h>
      68             : #include <casacore/casa/BasicSL/String.h>
      69             : #include <casacore/casa/Utilities/Assert.h>
      70             : #include <casacore/casa/Utilities/BinarySearch.h>
      71             : #include <casacore/casa/Exceptions/Error.h>
      72             : #include <casacore/scimath/Mathematics/NNGridder.h>
      73             : #include <casacore/scimath/Mathematics/ConvolveGridder.h>
      74             : #include <casacore/measures/Measures/UVWMachine.h>
      75             : 
      76             : #include <casacore/casa/System/ProgressMeter.h>
      77             : 
      78             : #include <casacore/casa/OS/Timer.h>
      79             : #include <sstream>
      80             : #include <iostream>
      81             : #include <iomanip>
      82             : using namespace casacore;
      83             : namespace casa{//# CASA namespace
      84             : namespace refim {//# namespace refactor imaging
      85             : 
      86             : using namespace casacore;
      87             : using namespace casa;
      88             : using namespace casacore;
      89             : using namespace casa::refim;
      90             : using namespace casacore;
      91             : using namespace casa::vi;
      92           6 :   FTMachine::FTMachine() : isDryRun(false), image(0), uvwMachine_p(0),
      93           6 :                            tangentSpecified_p(false), fixMovingSource_p(false),
      94           3 :                            ephemTableName_p(""),
      95           3 :                            movingDirShift_p(0.0),
      96           3 :                            distance_p(0.0), lastFieldId_p(-1),lastMSId_p(-1), romscol_p(nullptr),
      97           3 :                            useDoubleGrid_p(false),
      98           3 :                            freqFrameValid_p(false),
      99           3 :                            freqInterpMethod_p(InterpolateArray1D<Double,Complex>::nearestNeighbour),
     100           3 :                            pointingDirCol_p("DIRECTION"),
     101           3 :                            cfStokes_p(), cfCache_p(), cfs_p(), cfwts_p(), cfs2_p(), cfwts2_p(),
     102           3 :                            canComputeResiduals_p(false), toVis_p(true),
     103          15 :                            numthreads_p(-1), pbLimit_p(0.05),sj_p(0), cmplxImage_p( ), vbutil_p(), phaseCenterTime_p(-1.0), doneThreadPartition_p(-1), briggsWeightor_p(nullptr), tempFileNames_p(0), ftmType_p(FTMachine::CORRECTED), avgPBReady_p(false)
     104             :   {
     105           3 :     spectralCoord_p=SpectralCoordinate();
     106           3 :     isPseudoI_p=false;
     107           3 :     spwChanSelFlag_p=0;
     108           3 :     polInUse_p=0;
     109           3 :     pop_p = new PolOuterProduct;
     110           3 :     ft_p=FFT2D(true);
     111           3 :   }
     112             : 
     113           0 :   FTMachine::FTMachine(CountedPtr<CFCache>& cfcache,CountedPtr<ConvolutionFunction>& cf):
     114           0 :     isDryRun(false), image(0), uvwMachine_p(0),
     115           0 :     tangentSpecified_p(false), fixMovingSource_p(false),
     116           0 :     ephemTableName_p(""),
     117           0 :     movingDirShift_p(0.0),
     118           0 :     distance_p(0.0), lastFieldId_p(-1),lastMSId_p(-1), romscol_p(nullptr),
     119           0 :     useDoubleGrid_p(false),
     120           0 :     freqFrameValid_p(false),
     121           0 :     freqInterpMethod_p(InterpolateArray1D<Double,Complex>::nearestNeighbour),
     122           0 :     pointingDirCol_p("DIRECTION"),
     123           0 :     cfStokes_p(), cfCache_p(cfcache), cfs_p(), cfwts_p(), cfs2_p(), cfwts2_p(),
     124           0 :     convFuncCtor_p(cf),canComputeResiduals_p(false), toVis_p(true), numthreads_p(-1),
     125           0 :     pbLimit_p(0.05),sj_p(0), cmplxImage_p( ), vbutil_p(), phaseCenterTime_p(-1.0), doneThreadPartition_p(-1), briggsWeightor_p(nullptr), tempFileNames_p(0), ftmType_p(FTMachine::CORRECTED), avgPBReady_p(false)
     126             :   {
     127           0 :     spectralCoord_p=SpectralCoordinate();
     128           0 :     isPseudoI_p=false;
     129           0 :     spwChanSelFlag_p=0;
     130           0 :     polInUse_p=0;
     131           0 :     pop_p = new PolOuterProduct;
     132           0 :     ft_p=FFT2D(true);
     133           0 :   }
     134             : 
     135          25 :   LogIO& FTMachine::logIO() {return logIO_p;};
     136             : 
     137             :   //----------------------------------------------------------------------
     138           0 :   FTMachine& FTMachine::operator=(const FTMachine& other)
     139             :   {
     140           0 :     if(this!=&other) {
     141           0 :       image=other.image;
     142             :       //generic selection stuff and state
     143           0 :       nAntenna_p=other.nAntenna_p;
     144           0 :       distance_p=other.distance_p;
     145           0 :       lastFieldId_p=other.lastFieldId_p;
     146           0 :       lastMSId_p=other.lastMSId_p;
     147           0 :       romscol_p=other.romscol_p;
     148           0 :       tangentSpecified_p=other.tangentSpecified_p;
     149           0 :       mTangent_p=other.mTangent_p;
     150           0 :       mImage_p=other.mImage_p;
     151           0 :       mFrame_p=other.mFrame_p;
     152             : 
     153           0 :       nx=other.nx;
     154           0 :       ny=other.ny;
     155           0 :       npol=other.npol;
     156           0 :       nchan=other.nchan;
     157           0 :       nvischan=other.nvischan;
     158           0 :       nvispol=other.nvispol;
     159           0 :       mLocation_p=other.mLocation_p;
     160           0 :       if(uvwMachine_p)
     161           0 :           delete uvwMachine_p;
     162           0 :       if(other.uvwMachine_p)
     163           0 :         uvwMachine_p=new casacore::UVWMachine(*other.uvwMachine_p);
     164             :       else
     165           0 :         uvwMachine_p=0;
     166           0 :       doUVWRotation_p=other.doUVWRotation_p;
     167             :       //Spectral and pol stuff
     168           0 :       freqInterpMethod_p=other.freqInterpMethod_p;
     169           0 :       spwChanSelFlag_p.resize();
     170           0 :       spwChanSelFlag_p=other.spwChanSelFlag_p;
     171           0 :       freqFrameValid_p=other.freqFrameValid_p;
     172             :       //selectedSpw_p.resize();
     173             :       //selectedSpw_p=other.selectedSpw_p;
     174           0 :       imageFreq_p.resize();
     175           0 :       imageFreq_p=other.imageFreq_p;
     176           0 :       lsrFreq_p.resize();
     177           0 :       lsrFreq_p=other.lsrFreq_p;
     178           0 :       interpVisFreq_p.resize();
     179           0 :       interpVisFreq_p=other.interpVisFreq_p;
     180             :       //multiChanMap_p=other.multiChanMap_p;
     181           0 :       chanMap.resize();
     182           0 :       chanMap=other.chanMap;
     183           0 :       polMap.resize();
     184           0 :       polMap=other.polMap;
     185           0 :       nVisChan_p.resize();
     186           0 :       nVisChan_p=other.nVisChan_p;
     187           0 :       spectralCoord_p=other.spectralCoord_p;
     188           0 :       visPolMap_p.resize();
     189           0 :       visPolMap_p=other.visPolMap_p;
     190             :       //doConversion_p.resize();
     191             :       //doConversion_p=other.doConversion_p;
     192           0 :       pointingDirCol_p=other.pointingDirCol_p;
     193             :       //moving source stuff
     194           0 :       movingDir_p=other.movingDir_p;
     195           0 :       fixMovingSource_p=other.fixMovingSource_p;
     196           0 :       ephemTableName_p = other.ephemTableName_p;
     197           0 :       firstMovingDir_p=other.firstMovingDir_p;
     198           0 :       movingDirShift_p=other.movingDirShift_p;
     199             :       //Double precision gridding for those FTMachines that can do
     200           0 :       useDoubleGrid_p=other.useDoubleGrid_p;
     201           0 :       cfStokes_p = other.cfStokes_p;
     202           0 :       polInUse_p = other.polInUse_p;
     203           0 :       cfs_p = other.cfs_p;
     204           0 :       cfwts_p = other.cfwts_p;
     205           0 :       cfs2_p = other.cfs2_p;
     206           0 :       cfwts2_p = other.cfwts2_p;
     207           0 :       canComputeResiduals_p = other.canComputeResiduals_p;
     208             : 
     209           0 :       pop_p = other.pop_p;
     210           0 :       toVis_p = other.toVis_p;
     211           0 :       spwFreqSel_p.resize();
     212           0 :       spwFreqSel_p = other.spwFreqSel_p;
     213           0 :       expandedSpwFreqSel_p = other.expandedSpwFreqSel_p;
     214           0 :       expandedSpwConjFreqSel_p = other.expandedSpwConjFreqSel_p;
     215           0 :       cmplxImage_p=other.cmplxImage_p;
     216           0 :       vbutil_p=other.vbutil_p;
     217           0 :       numthreads_p=other.numthreads_p;
     218           0 :       pbLimit_p=other.pbLimit_p;
     219           0 :       convFuncCtor_p = other.convFuncCtor_p;
     220           0 :       sj_p.resize();
     221           0 :       sj_p=other.sj_p;
     222           0 :       isDryRun=other.isDryRun;
     223           0 :       phaseCenterTime_p=other.phaseCenterTime_p;
     224           0 :       doneThreadPartition_p=other.doneThreadPartition_p;
     225           0 :       xsect_p=other.xsect_p;
     226           0 :       ysect_p=other.ysect_p;
     227           0 :       nxsect_p=other.nxsect_p;
     228           0 :       nysect_p=other.nysect_p;
     229           0 :       obsvelconv_p=other.obsvelconv_p;
     230           0 :       mtype_p=other.mtype_p;
     231           0 :       briggsWeightor_p=other.briggsWeightor_p;
     232           0 :       ft_p=other.ft_p;
     233           0 :       ftmType_p = other.ftmType_p;
     234           0 :       avgPBReady_p = other.avgPBReady_p;
     235             :     };
     236           0 :     return *this;
     237             :   };
     238             : 
     239           0 :   FTMachine* FTMachine::cloneFTM(){
     240           0 :     Record rec;
     241           0 :     String err;
     242           0 :     if(!(this->toRecord(err, rec)))
     243           0 :       throw(AipsError("Error in cloning FTMachine"));
     244           0 :     FTMachine* retval=VisModelData::NEW_FT(rec);
     245           0 :     if(retval)
     246           0 :       retval->briggsWeightor_p=briggsWeightor_p;
     247           0 :     return retval;
     248           0 :   }
     249             : 
     250             :   //----------------------------------------------------------------------
     251           0 :   Bool FTMachine::changed(const vi::VisBuffer2&) {
     252           0 :       return false;
     253             :     }
     254             :   //----------------------------------------------------------------------
     255           0 :   FTMachine::FTMachine(const FTMachine& other)
     256             :   {
     257           0 :     operator=(other);
     258           0 :   }
     259             : 
     260           0 :   Bool FTMachine::doublePrecGrid(){
     261           0 :     return useDoubleGrid_p;
     262             :   }
     263             : 
     264           0 :   void FTMachine::reset(){
     265             :     //ft_p=FFT2D(true);
     266           0 :   }
     267             : 
     268             :   //----------------------------------------------------------------------
     269           6 :    void FTMachine::initPolInfo(const vi::VisBuffer2& vb)
     270             :    {
     271             :      //
     272             :      // Need to figure out where to compute the following arrays/ints
     273             :      // in the re-factored code.
     274             :      // ----------------------------------------------------------------
     275             :      {
     276           6 :        polInUse_p = 0;
     277           6 :        uInt N=0;
     278          30 :        for(uInt i=0;i<polMap.nelements();i++) if (polMap(i) > -1) polInUse_p++;
     279           6 :        cfStokes_p.resize(polInUse_p);
     280          30 :        for(uInt i=0;i<polMap.nelements();i++)
     281          24 :         if (polMap(i) > -1) {cfStokes_p(N) = vb.correlationTypes()(i);N++;}
     282             :      }
     283           6 :    }
     284             :   //----------------------------------------------------------------------
     285           6 :     void FTMachine::initMaps(const vi::VisBuffer2& vb) {
     286           6 :       logIO() << LogOrigin("FTMachine", "initMaps") << LogIO::NORMAL;
     287             : 
     288           6 :       AlwaysAssert(image, AipsError);
     289             : 
     290             :       // Set the frame for the UVWMachine
     291           6 :       if(vb.isAttached()){
     292             :         //mFrame_p=MeasFrame(MEpoch(Quantity(vb.time()(0), "s"), MSColumns(vb.ms()).timeMeas()(0).getRef()), mLocation_p);
     293           6 :         if(vbutil_p.null())
     294           3 :           vbutil_p=new VisBufferUtil(vb);
     295           6 :         romscol_p=new MSColumns(vb.ms());
     296          12 :         Unit epochUnit=(romscol_p->time()).keywordSet().asArrayString("QuantumUnits")(IPosition(1,0));
     297           6 :         if(!mFrame_p.epoch())
     298           3 :           mFrame_p.set(MEpoch(Quantity(vb.time()(0), epochUnit),  (romscol_p->timeMeas())(0).getRef()));
     299             :         else
     300           3 :           mFrame_p.resetEpoch(MEpoch(Quantity(vb.time()(0), epochUnit), (romscol_p->timeMeas())(0).getRef()));
     301           6 :         if(!mFrame_p.position())
     302           3 :           mFrame_p.set(mLocation_p);
     303             :         else
     304           3 :           mFrame_p.resetPosition(mLocation_p);
     305           6 :         if(!mFrame_p.direction())
     306           3 :           mFrame_p.set(vbutil_p->getEphemDir(vb, phaseCenterTime_p));
     307             :         else
     308           3 :           mFrame_p.resetDirection(vbutil_p->getEphemDir(vb, phaseCenterTime_p));
     309           6 :       }
     310             :       else{
     311           0 :         throw(AipsError("Cannot define some frame as no Visiter/MS is attached"));
     312             :       }
     313             :       //////TESTOOOO
     314             :       ///setMovingSource("COMET", "des_deedee_ephem2.tab");
     315             :       ///////////////////////////////////////////
     316             :       // First get the CoordinateSystem for the image and then find
     317             :       // the DirectionCoordinate
     318           6 :       casacore::CoordinateSystem coords=image->coordinates();
     319           6 :       Int directionIndex=coords.findCoordinate(Coordinate::DIRECTION);
     320           6 :       AlwaysAssert(directionIndex>=0, AipsError);
     321             :       DirectionCoordinate
     322           6 :         directionCoord=coords.directionCoordinate(directionIndex);
     323           6 :       Int spectralIndex=coords.findCoordinate(Coordinate::SPECTRAL);
     324           6 :       AlwaysAssert(spectralIndex>-1, AipsError);
     325           6 :       spectralCoord_p=coords.spectralCoordinate(spectralIndex);
     326             : 
     327             :       // get the first position of moving source
     328           6 :       if(fixMovingSource_p){
     329             :         //cerr << "obsinfo time " << coords.obsInfo().obsDate() << "    epoch used in frame " <<  MEpoch((mFrame_p.epoch())) << endl;
     330             :         ///Darn vb.time()(0) may not be the earliest time due to sort issues...
     331             :         //so lets try to use the same
     332             :         ///time as SynthesisIUtilMethods::buildCoordinateSystemCore is using
     333             :         //mFrame_p.resetEpoch(romscol_p->timeMeas()(0));
     334           0 :         mFrame_p.resetEpoch(coords.obsInfo().obsDate());
     335             :         //Double firstTime=romscol_p->time()(0);
     336             : 
     337           0 :         Double firstTime=coords.obsInfo().obsDate().get("s").getValue();
     338             :         //First convert to HA-DEC or AZEL for parallax correction
     339           0 :         MDirection::Ref outref1(MDirection::AZEL, mFrame_p);
     340           0 :         MDirection tmphadec;
     341           0 :         if (upcase(movingDir_p.getRefString()).contains("APP")) {
     342             :           //cerr << "phaseCenterTime_p " << phaseCenterTime_p << endl;
     343           0 :           tmphadec = MDirection::Convert((vbutil_p->getEphemDir(vb, phaseCenterTime_p > 0.0 ? phaseCenterTime_p : firstTime)), outref1)();
     344           0 :           MeasComet mcomet(Path((romscol_p->field()).ephemPath(vb.fieldId()(0))).absoluteName());
     345           0 :           if (mFrame_p.comet())
     346           0 :             mFrame_p.resetComet(mcomet);
     347             :           else
     348           0 :             mFrame_p.set(mcomet);
     349           0 :         } else if (upcase(movingDir_p.getRefString()).contains("COMET")) {
     350           0 :           MeasComet mcomet(Path(ephemTableName_p).absoluteName());
     351           0 :           if (mFrame_p.comet())
     352           0 :             mFrame_p.resetComet(mcomet);
     353             :           else
     354           0 :             mFrame_p.set(mcomet);
     355           0 :           tmphadec = MDirection::Convert(MDirection(MDirection::COMET), outref1)();
     356           0 :         } else {
     357           0 :           tmphadec = MDirection::Convert(movingDir_p, outref1)();
     358             :         }
     359           0 :         MDirection::Ref outref(directionCoord.directionType(), mFrame_p);
     360           0 :         firstMovingDir_p=MDirection::Convert(tmphadec, outref)();
     361             :         ////////////////////
     362             :         /*ostringstream ss;
     363             :         Unit epochUnit=(romscol_p->time()).keywordSet().asArrayString("QuantumUnits")(IPosition(1,0));
     364             :         MEpoch(Quantity(vb.time()(0), epochUnit), (romscol_p->timeMeas())(0).getRef()).print(ss);
     365             :         cerr << std::setprecision(15) << "First time " << ss.str() << "field id " << vb.fieldId()(0) << endl;
     366             :         ss.clear();
     367             :         firstMovingDir_p.print(ss);
     368             :         cerr << "firstdir " << ss.str() << "   " << firstMovingDir_p.toString() << endl;
     369             :         */
     370             :         //////////////
     371             : 
     372           0 :         if(spectralCoord_p.frequencySystem(False)==MFrequency::REST){
     373             :           ///We want the data frequency to be shifted to the SOURCE frame
     374             :           ///which is labelled REST as we have never defined the SOURCE frame didn't we
     375           0 :           initSourceFreqConv();
     376             :         }
     377             :         ///TESTOO
     378             :         ///waiting for CAS-11060
     379             :         //firstMovingDir_p=MDirection::Convert(vbutil_p->getPhaseCenter(vb, phaseCenterTime_p), outref)();
     380             :         ////////////////////
     381           0 :       }
     382             : 
     383             : 
     384             :       // Now we need MDirection of the image phase center. This is
     385             :       // what we define it to be. So we define it to be the
     386             :       // center pixel. So we have to do the conversion here.
     387             :       // This is independent of padding since we just want to know
     388             :       // what the world coordinates are for the phase center
     389             :       // pixel
     390             :       {
     391           6 :         Vector<Double> pixelPhaseCenter(2);
     392           6 :         pixelPhaseCenter(0) = Double( image->shape()(0) / 2 );
     393           6 :         pixelPhaseCenter(1) = Double( image->shape()(1) / 2 );
     394           6 :         directionCoord.toWorld(mImage_p, pixelPhaseCenter);
     395           6 :       }
     396             : 
     397             :       // Get the object distance in meters
     398           6 :       Record info(image->miscInfo());
     399           6 :       if(info.isDefined("distance")) {
     400           0 :         info.get("distance", distance_p);
     401           0 :         if(abs(distance_p)>0.0) {
     402           0 :         logIO() << "Distance to object is set to " << distance_p/1000.0
     403           0 :                 << "km: applying focus correction" << LogIO::POST;
     404             :         }
     405             :       }
     406             : 
     407             :       // Set up the UVWMachine.
     408           6 :       initUVWMachine(vb);
     409             : 
     410           6 :       lastFieldId_p=-1;
     411             : 
     412           6 :       lastMSId_p=vb.msId();
     413             : 
     414             :       // Set up maps
     415             : 
     416             : 
     417             : 
     418             :       //Store the image/grid channels freq values
     419             :       {
     420           6 :         Int chanNumbre=image->shape()(3);
     421           6 :         Vector<Double> pixindex(chanNumbre);
     422           6 :         imageFreq_p.resize(chanNumbre);
     423           6 :         Vector<Double> tempStorFreq(chanNumbre);
     424           6 :         indgen(pixindex);
     425             :         //    pixindex=pixindex+1.0;
     426          12 :         for (Int ll=0; ll< chanNumbre; ++ll){
     427           6 :         if( !spectralCoord_p.toWorld(tempStorFreq(ll), pixindex(ll))){
     428           0 :           logIO() << "Cannot get imageFreq " << LogIO::EXCEPTION;
     429             : 
     430             :         }
     431             :         }
     432           6 :         convertArray(imageFreq_p,tempStorFreq);
     433           6 :       }
     434             :       //Destroy any conversion layer Freq coord if freqframe is not valid
     435           6 :       if(!freqFrameValid_p){
     436           6 :         MFrequency::Types imageFreqType=spectralCoord_p.frequencySystem();
     437           6 :         spectralCoord_p.setFrequencySystem(imageFreqType);
     438           6 :         spectralCoord_p.setReferenceConversion(imageFreqType,
     439          12 :                                              MEpoch(Quantity(vb.time()(0), "s")),
     440           6 :                                              mLocation_p,
     441           6 :                                              mImage_p);
     442             :       }
     443             : 
     444             :       // Channel map: do this properly by looking up the frequencies
     445             :       // If a visibility channel does not map onto an image
     446             :       // pixel then we set the corresponding chanMap to -1.
     447             :       // This means that put and get must always check for this
     448             :       // value (see e.g. GridFT)
     449             : 
     450           6 :       nvischan  = vb.getFrequencies(0).nelements();
     451           6 :       interpVisFreq_p.resize();
     452           6 :       interpVisFreq_p=vb.getFrequencies(0);
     453             : 
     454             :       // Polarization map
     455           6 :       visPolMap_p.resize();
     456           6 :       polMap.resize();
     457             : 
     458             :       //As matchChannel calls matchPol ...it has to be called after making sure
     459             :       //polMap and visPolMap are zero size to force a polMap matching
     460           6 :       chanMap.resize();
     461           6 :       matchChannel(vb);
     462             :       //chanMap=multiChanMap_p[vb.spectralWindows()(0)];
     463           6 :       if(chanMap.nelements() == 0)
     464           0 :         chanMap=Vector<Int>(vb.getFrequencies(0).nelements(), -1);
     465             : 
     466             :       {
     467             :         //logIO() << LogIO::DEBUGGING << "Channel Map: " << chanMap << LogIO::POST;
     468             :       }
     469             :       // Should never get here
     470           6 :       if(max(chanMap)>=nchan||min(chanMap)<-2) {
     471           0 :         logIO() << "Illegal Channel Map: " << chanMap << LogIO::EXCEPTION;
     472             :       }
     473             : 
     474             : 
     475           6 :       initPolInfo(vb);
     476           6 :       Vector<Int> intpolmap(visPolMap_p.nelements());
     477          30 :       for (uInt kk=0; kk < intpolmap.nelements(); ++kk){
     478          24 :         intpolmap[kk]=Int(visPolMap_p[kk]);
     479             :       }
     480           6 :       pop_p->initCFMaps(intpolmap, polMap);
     481             : 
     482             : 
     483             : 
     484             : 
     485             : 
     486             : 
     487             : 
     488           6 :     }
     489             : 
     490           6 :   void FTMachine::initUVWMachine(const vi::VisBuffer2& vb) {
     491             :     // Decide if uvwrotation is not necessary, if phasecenter and
     492             :     // image center are with in one pixel distance; Save some
     493             :     //  computation time especially for spectral cubes.
     494           6 :     casacore::CoordinateSystem coords=image->coordinates();
     495           6 :     Int directionIndex=coords.findCoordinate(Coordinate::DIRECTION);
     496           6 :     AlwaysAssert(directionIndex>=0, AipsError);
     497           6 :     auto const directionCoord=coords.directionCoordinate(directionIndex);
     498          12 :     Vector<Double> equal= (mImage_p.getAngle()-
     499          18 :                 vbutil_p->getPhaseCenter(vb, phaseCenterTime_p).getAngle()).getValue();
     500          18 :     if((abs(equal(0)) < abs(directionCoord.increment()(0)))
     501          18 :             && (abs(equal(1)) < abs(directionCoord.increment()(1)))){
     502           6 :             doUVWRotation_p=false;
     503             :     } else {
     504           0 :             doUVWRotation_p=true;
     505             :     }
     506             : 
     507           6 :     if(uvwMachine_p) delete uvwMachine_p; uvwMachine_p=0;
     508           6 :     String observatory;
     509           6 :     if(vb.isAttached())
     510           6 :             observatory=(vb.subtableColumns().observation()).telescopeName()(0);
     511             :     else
     512           0 :             throw(AipsError("Cannot define frame because of no access to OBSERVATION table"));
     513          12 :     if(observatory.contains("ATCA") || observatory.contains("DRAO")
     514          12 :         || observatory.contains("WSRT")){
     515           0 :         uvwMachine_p=new casacore::UVWMachine(mImage_p, vbutil_p->getPhaseCenter(vb, phaseCenterTime_p), mFrame_p,
     516           0 :                                   true, false);
     517             :     } else {
     518          12 :         uvwMachine_p=new casacore::UVWMachine(mImage_p, vbutil_p->getPhaseCenter(vb, phaseCenterTime_p), mFrame_p,
     519           6 :                                   false, tangentSpecified_p);
     520             :     }
     521           6 :     AlwaysAssert(uvwMachine_p, AipsError);
     522             : 
     523           6 :     phaseShifter_p=new UVWMachine(*uvwMachine_p);
     524           6 :   }
     525             : 
     526           0 :   void FTMachine::initBriggsWeightor(vi::VisibilityIterator2& vi){
     527             :     ///Lastly initialized Briggs cube weighting scheme
     528           0 :     if(!briggsWeightor_p.null()){
     529           0 :       String error;
     530           0 :       Record rec;
     531           0 :       AlwaysAssert(image, AipsError);
     532           0 :       if(!toRecord(error, rec))
     533           0 :         throw (AipsError("Could not initialize BriggsWeightor"));
     534           0 :       String wgtcolname=briggsWeightor_p->initImgWeightCol(vi, *image, rec);
     535           0 :       tempFileNames_p.resize(tempFileNames_p.nelements()+1, True);
     536           0 :       tempFileNames_p[tempFileNames_p.nelements()-1]=wgtcolname;
     537             : 
     538           0 :     }
     539           0 :   }
     540             : 
     541           0 :   FTMachine::~FTMachine()
     542             :   {
     543           0 :     if(uvwMachine_p) delete uvwMachine_p; uvwMachine_p=0;
     544           0 :   }
     545             : 
     546             : 
     547           0 :   void FTMachine::initSourceFreqConv(){
     548           0 :     MRadialVelocity::Types refvel=MRadialVelocity::GEO;
     549           0 :     if(mFrame_p.comet()){
     550             :       //Has a ephem table
     551           0 :       if(((mFrame_p.comet())->getTopo().getLength("km").getValue()) > 1.0e-3){
     552           0 :         refvel=MRadialVelocity::TOPO;
     553             :       }
     554             : 
     555             : 
     556             :     }
     557             :     else{
     558             :       //using a canned DE-200 or 405 source
     559           0 :       MDirection::Types planetType=MDirection::castType(movingDir_p.getRef().getType());
     560           0 :     mtype_p=MeasTable::BARYEARTH;
     561           0 :     if(planetType >=MDirection::MERCURY && planetType <MDirection::COMET){
     562             :       //Damn these enums are not in the same order
     563           0 :       switch(planetType){
     564           0 :       case MDirection::MERCURY :
     565           0 :         mtype_p=MeasTable::MERCURY;
     566           0 :         break;
     567           0 :       case MDirection::VENUS :
     568           0 :         mtype_p=MeasTable::VENUS;
     569           0 :         break;
     570           0 :       case MDirection::MARS :
     571           0 :         mtype_p=MeasTable::MARS;
     572           0 :         break;
     573           0 :       case MDirection::JUPITER :
     574           0 :         mtype_p=MeasTable::JUPITER;
     575           0 :         break;
     576           0 :       case MDirection::SATURN :
     577           0 :         mtype_p=MeasTable::SATURN;
     578           0 :         break;
     579           0 :       case MDirection::URANUS :
     580           0 :         mtype_p=MeasTable::URANUS;
     581           0 :         break;
     582           0 :       case MDirection::NEPTUNE :
     583           0 :         mtype_p=MeasTable::NEPTUNE;
     584           0 :         break;
     585           0 :       case MDirection::PLUTO :
     586           0 :         mtype_p=MeasTable::PLUTO;
     587           0 :         break;
     588           0 :       case MDirection::MOON :
     589           0 :         mtype_p=MeasTable::MOON;
     590           0 :         break;
     591           0 :       case MDirection::SUN :
     592           0 :         mtype_p=MeasTable::SUN;
     593           0 :         break;
     594           0 :       default:
     595           0 :         throw(AipsError("Cannot translate to known major solar system object"));
     596             :       }
     597             : 
     598             :     }
     599             : 
     600             :     }
     601           0 :      obsvelconv_p=MRadialVelocity::Convert (MRadialVelocity(MVRadialVelocity(0.0),
     602           0 :                                                          MRadialVelocity::Ref(MRadialVelocity::TOPO, mFrame_p)),
     603           0 :                                                          MRadialVelocity::Ref(refvel));
     604             : 
     605           0 :   }
     606             : 
     607             : 
     608           0 :   Long FTMachine::estimateRAM(const CountedPtr<SIImageStore>& imstor){
     609             :     //not set up yet
     610           0 :     if(!image && !imstor)
     611           0 :       return -1;
     612           0 :     Long npixels=0;
     613           0 :     if(image)
     614           0 :       npixels=((image->shape()).product())/1024;
     615             :     else{
     616           0 :       if((imstor->getShape()).product() !=0)
     617           0 :         npixels=(imstor->getShape()).product()/1024;
     618             :     }
     619           0 :     if(npixels==0) npixels=1; //1 kPixels is minimum then
     620           0 :     Long factor=sizeof(Complex);
     621           0 :     if(!toVis_p && useDoubleGrid_p)
     622           0 :       factor=sizeof(DComplex);
     623           0 :     return (npixels*factor);
     624             :   }
     625             : 
     626           0 :   void FTMachine::shiftFreqToSource(Vector<Double>& freqs){
     627           0 :     MDoppler dopshift;
     628           0 :     MEpoch ep(mFrame_p.epoch());
     629           0 :     if(mFrame_p.comet()){
     630             :       ////Will use UT for now for ephem tables as it is not clear that they are being
     631             :       ///filled with TDB as intended in MeasComet.h
     632           0 :       MEpoch::Convert toUT(ep, MEpoch::UT);
     633           0 :       MVRadialVelocity cometvel;
     634           0 :       (*mFrame_p.comet()).getRadVel(cometvel, toUT(ep).get("d").getValue());
     635             :       //cerr << std::setprecision(10) << "UT " << toUT(ep).get("d").getValue() << " cometvel " << cometvel.get("km/s").getValue("km/s") << endl;
     636             : 
     637             :       //cerr  << "pos " << MPosition(mFrame_p.position()) << " obsevatory vel " << obsvelconv_p().get("km/s").getValue("km/s") << endl;
     638           0 :       dopshift=MDoppler(Quantity(-cometvel.get("km/s").getValue("km/s")+obsvelconv_p().get("km/s").getValue("km/s") , "km/s"), MDoppler::RELATIVISTIC);
     639             : 
     640           0 :     }
     641             :     else{
     642           0 :        Vector<Double> planetparam;
     643           0 :        Vector<Double> earthparam;
     644           0 :        MEpoch::Convert toTDB(ep, MEpoch::TDB);
     645           0 :        earthparam=MeasTable::Planetary(MeasTable::EARTH, toTDB(ep).get("d").getValue());
     646           0 :        planetparam=MeasTable::Planetary(mtype_p, toTDB(ep).get("d").getValue());
     647             :        //GEOcentric param
     648           0 :        planetparam=planetparam-earthparam;
     649           0 :        Vector<Double> unitdirvec(3);
     650           0 :        Double dist=sqrt(planetparam(0)*planetparam(0)+planetparam(1)*planetparam(1)+planetparam(2)*planetparam(2));
     651           0 :        unitdirvec(0)=planetparam(0)/dist;
     652           0 :        unitdirvec(1)=planetparam(1)/dist;
     653           0 :        unitdirvec(2)=planetparam(2)/dist;
     654           0 :        Quantity planetradvel(planetparam(3)*unitdirvec(0)+planetparam(4)*unitdirvec(1)+planetparam(5)*unitdirvec(2), "AU/d");
     655           0 :         dopshift=MDoppler(Quantity(-planetradvel.getValue("km/s")+obsvelconv_p().get("km/s").getValue("km/s") , "km/s"), MDoppler::RELATIVISTIC);
     656             : 
     657           0 :     }
     658             : 
     659           0 :     Vector<Double> newfreqs=dopshift.shiftFrequency(freqs);
     660           0 :     freqs=newfreqs;
     661           0 :   }
     662             : 
     663         600 :   Bool FTMachine::interpolateFrequencyTogrid(const vi::VisBuffer2& vb,
     664             :                                              const Matrix<Float>& wt,
     665             :                                              Cube<Complex>& data,
     666             :                                              Cube<Int>& flags,
     667             :                                              Matrix<Float>& weight,
     668             :                                              FTMachine::Type type){
     669         600 :       Cube<Complex> origdata;
     670         600 :       Cube<Bool> modflagCube;
     671             :       // Read flags from the vb.
     672         600 :       setSpectralFlag(vb,modflagCube);
     673         600 :       Vector<Double> visFreq(vb.getFrequencies(0).nelements());
     674             :       //if(doConversion_p[vb.spectralWindows()[0]]){
     675         600 :       if(freqFrameValid_p){
     676           0 :         visFreq.resize(lsrFreq_p.shape());
     677           0 :         convertArray(visFreq, lsrFreq_p);
     678             :       }
     679             :       else{
     680         600 :         convertArray(visFreq, vb.getFrequencies(0));
     681         600 :         lsrFreq_p.resize();
     682         600 :         lsrFreq_p=vb.getFrequencies(0);
     683             :       }
     684         600 :       if(type==FTMachine::MODEL){
     685           0 :         origdata.reference(vb.visCubeModel());
     686             :       }
     687         600 :       else if(type==FTMachine::CORRECTED){
     688           0 :         origdata.reference(vb.visCubeCorrected());
     689             :       }
     690         600 :       else if(type==FTMachine::OBSERVED){
     691         600 :         origdata.reference(vb.visCube());
     692             :       }
     693           0 :       else if(type==FTMachine::PSF){
     694             :         // make sure its a size 0 data ...psf
     695             :         //so avoid reading any data from disk
     696           0 :         origdata.resize();
     697             : 
     698             :       }
     699             :       else{
     700           0 :         throw(AipsError("Don't know which column is being regridded"));
     701             :       }
     702         600 :       if((imageFreq_p.nelements()==1) || (freqInterpMethod_p== InterpolateArray1D<Double, Complex>::nearestNeighbour) || (vb.nChannels()==1)){
     703         600 :         data.reference(origdata);
     704             :         // do something here for apply flag based on spw chan sels
     705             :         // e.g.
     706             : 
     707             : 
     708         600 :         flags.resize(modflagCube.shape());
     709         600 :         flags=0;
     710             :         //flags(vb.flagCube())=true;
     711             : 
     712         600 :         flags(modflagCube)=true;
     713             : 
     714         600 :         weight.reference(wt);
     715         600 :         interpVisFreq_p.resize();
     716         600 :         interpVisFreq_p=lsrFreq_p;
     717             :         //cerr << "INTERPTOGRID " << interpVisFreq_p.nelements() << " vb.nchan  " << vb.nChannels() << endl;
     718         600 :         return false;
     719             :       }
     720             : 
     721           0 :       Cube<Bool>flag;
     722             : 
     723             :       //okay at this stage we have at least 2 channels
     724           0 :       Double width=fabs(imageFreq_p[1]-imageFreq_p[0])/fabs(visFreq[1]-visFreq[0]);
     725             :       //if width is smaller than number of points needed for interpolation ...do it directly
     726             :       //
     727             :       // If image chan width is more than twice the data chan width, make a new list of
     728             :       // data frequencies on which to interpolate. This new list is sync'd with the starting image chan
     729             :       // and have the same width as the data chans.
     730             :       /*if(((width >2.0) && (freqInterpMethod_p==InterpolateArray1D<Double, Complex>::linear)) ||
     731             :          ((width >4.0) && (freqInterpMethod_p !=InterpolateArray1D<Double, Complex>::linear))){
     732             :       */
     733           0 :       if(width > 1.0){
     734           0 :         Double minVF=min(visFreq);
     735           0 :         Double maxVF=max(visFreq);
     736           0 :         Double minIF=min(imageFreq_p);
     737           0 :         Double maxIF=max(imageFreq_p);
     738           0 :         if( ((minIF-fabs(imageFreq_p[1]-imageFreq_p[0])/2.0) > maxVF) ||
     739           0 :           ((maxIF+fabs(imageFreq_p[1]-imageFreq_p[0])/2.0) < minVF)){
     740             :         //This function should not have been called with image
     741             :         //being out of bound of data...but still
     742           0 :         interpVisFreq_p.resize(imageFreq_p.nelements());
     743           0 :         interpVisFreq_p=imageFreq_p;
     744           0 :         chanMap.resize(interpVisFreq_p.nelements());
     745           0 :         chanMap.set(-1);
     746             :         }
     747             :         else{ // Make a new list of frequencies.
     748             :         Bool found;
     749           0 :         uInt where=0;
     750             :         //Double interpwidth=visFreq[1]-visFreq[0];
     751           0 :         Double interpwidth=copysign(fabs(imageFreq_p[1]-imageFreq_p[0])/floor(width), visFreq[1]-visFreq[0]);
     752             :         //if(name() != "GridFT")
     753             :         //  cerr << "width " << width << " interpwidth " << interpwidth << endl;
     754           0 :         if(minIF < minVF){ // Need to find the first image-channel with data in it
     755           0 :           where=binarySearchBrackets(found, imageFreq_p, minVF, imageFreq_p.nelements());
     756           0 :           if(where != imageFreq_p.nelements()){
     757           0 :             minIF=imageFreq_p[where];
     758             :           }
     759             :         }
     760             : 
     761           0 :         if(maxIF > maxVF){
     762           0 :            where=binarySearchBrackets(found, imageFreq_p, maxVF, imageFreq_p.nelements());
     763           0 :            if(where!= imageFreq_p.nelements()){
     764           0 :             maxIF=imageFreq_p[where];
     765             :            }
     766             : 
     767             :         }
     768             : 
     769             :           // This new list of frequencies starts at the first image channel minus half image channel.
     770             :         // It ends at the last image channel plus half image channel.
     771           0 :         Int ninterpchan=(Int)ceil((maxIF-minIF+fabs(imageFreq_p[1]-imageFreq_p[0]))/fabs(interpwidth))+2;
     772           0 :         chanMap.resize(ninterpchan);
     773           0 :         chanMap.set(-1);
     774           0 :         interpVisFreq_p.resize(ninterpchan);
     775           0 :         interpVisFreq_p[0]=(interpwidth > 0) ? minIF : maxIF;
     776           0 :         if(freqInterpMethod_p==InterpolateArray1D<Double, Complex>::linear)
     777           0 :           interpVisFreq_p[0]-=interpwidth;
     778           0 :         if(freqInterpMethod_p==InterpolateArray1D<Double, Complex>::cubic)
     779           0 :           interpVisFreq_p[0]-=2.0*interpwidth;
     780           0 :         Double startedge=abs(imageFreq_p[1]-imageFreq_p[0])/2.0 -abs(interpwidth)/2.0;
     781           0 :         interpVisFreq_p[0] =(interpwidth >0) ? (interpVisFreq_p[0]-startedge):(interpVisFreq_p[0]+startedge);
     782             : 
     783           0 :         for (Int k=1; k < ninterpchan; ++k){
     784           0 :           interpVisFreq_p[k] = interpVisFreq_p[k-1]+ interpwidth;
     785             :         }
     786           0 :         Double halfdiff=fabs((imageFreq_p[1]-imageFreq_p[0])/2.0);
     787           0 :         for (Int k=0; k < ninterpchan; ++k){
     788             :           ///chanmap with width
     789             :           //      Double nearestchanval = interpVisFreq_p[k]- (imageFreq_p[1]-imageFreq_p[0])/2.0;
     790             :           //where=binarySearchBrackets(found, imageFreq_p, nearestchanval, imageFreq_p.nelements());
     791           0 :           Int which=-1;
     792           0 :           for (Int j=0; j< Int(imageFreq_p.nelements()); ++j){
     793             :             //cerr <<  (imageFreq_p[j]-halfdiff)  << "   "   << (imageFreq_p[j]+halfdiff) << " val " << interpVisFreq_p[k] << endl;
     794           0 :             if( (interpVisFreq_p[k] >= (imageFreq_p[j]-halfdiff)) && (interpVisFreq_p[k] <  (imageFreq_p[j]+halfdiff)))
     795           0 :               which=j;
     796             :           }
     797           0 :           if((which > -1) && (which < Int(imageFreq_p.nelements()))){
     798           0 :             chanMap[k]=which;
     799             :           }
     800             :           else{
     801             :             //if(name() != "GridFT")
     802             :             //  cerr << "MISSED it " << interpVisFreq_p[k] << endl;
     803             :           }
     804             : 
     805             : 
     806             :         }
     807             :         //        if(name() != "GridFT")
     808             :         //  cerr << std::setprecision(10) << "chanMap " << chanMap <<  endl; //" interpvisfreq " <<  interpVisFreq_p << " orig " << visFreq << endl;
     809             : 
     810             :         }// By now, we have a new list of frequencies, synchronized with image channels, but with data chan widths.
     811             :       }// end of ' if (we have to make new frequencies) '
     812             :       else{
     813             :         // Interpolate directly onto output image frequencies.
     814           0 :         interpVisFreq_p.resize(imageFreq_p.nelements());
     815           0 :         convertArray(interpVisFreq_p, imageFreq_p);
     816           0 :         chanMap.resize(interpVisFreq_p.nelements());
     817           0 :         indgen(chanMap);
     818             :       }
     819           0 :       if(type != FTMachine::PSF){ // Interpolating the data
     820             :         //Need to get  new interpolate functions that interpolate explicitly on the 2nd axis
     821             :         //2 swap of axes needed
     822           0 :         Cube<Complex> flipdata;
     823           0 :         Cube<Bool> flipflag;
     824             : 
     825             :           // Interpolate the data.
     826             :           //      Input flags are from the previous step ( setSpectralFlag ).
     827             :           //      Output flags contain info about channels that could not be interpolated
     828             :           //                                   (for example, linear interp with only one data point)
     829           0 :         swapyz(flipflag,modflagCube);
     830           0 :         swapyz(flipdata,origdata);
     831             :         InterpolateArray1D<Double,Complex>::
     832           0 :           interpolate(data,flag,interpVisFreq_p,visFreq,flipdata,flipflag,freqInterpMethod_p, False, False);
     833           0 :         flipdata.resize();
     834           0 :         swapyz(flipdata,data);
     835           0 :         data.resize();
     836           0 :         data.reference(flipdata);
     837           0 :         flipflag.resize();
     838           0 :         swapyz(flipflag,flag);
     839           0 :         flag.resize();
     840           0 :         flag.reference(flipflag);
     841             :         // Note : 'flag' will get augmented with the flags coming out of weight interpolation
     842           0 :       }
     843             :       else
     844             :         { // get the flag array to the correct shape.
     845             :           // This will get filled at the end of weight-interpolation.
     846           0 :           flag.resize(vb.nCorrelations(), interpVisFreq_p.nelements(), vb.nRows());
     847           0 :           flag.set(false);
     848             :         }
     849             :         // Now, interpolate the weights also.
     850             :         //   (1) Read in the flags from the vb ( setSpectralFlags -> modflagCube )
     851             :         //   (2) Collapse the flags along the polarization dimension to match shape of weight.
     852             :         //If BriggsWeightor is used weight is already interpolated so we can bypass this
     853           0 :          InterpolateArray1D<casacore::Double,casacore::Complex>::InterpolationMethod weightinterp=freqInterpMethod_p;
     854             : 
     855           0 :   if(!briggsWeightor_p.null()){
     856           0 :     weightinterp= InterpolateArray1D<casacore::Double,casacore::Complex>::nearestNeighbour;
     857             :   }
     858             :       //InterpolateArray1D<casacore::Double,casacore::Complex>::InterpolationMethod weightinterp=InterpolateArray1D<casacore::Double,casacore::Complex>::nearestNeighbour;
     859           0 :          Matrix<Bool> chanflag(wt.shape());
     860           0 :          AlwaysAssert( chanflag.shape()[0]==modflagCube.shape()[1], AipsError);
     861           0 :          AlwaysAssert( chanflag.shape()[1]==modflagCube.shape()[2], AipsError);
     862           0 :          chanflag=false;
     863           0 :          for(uInt pol=0;pol<modflagCube.shape()[0];pol++)
     864           0 :          chanflag = chanflag | modflagCube.yzPlane(pol);
     865             : 
     866             :          // (3) Interpolate the weights.
     867             :          //      Input flags are the collapsed vb flags : 'chanflag'
     868             :          //      Output flags are in tempoutputflag
     869             :          //            - contains info about channels that couldn't be interpolated.
     870           0 :          Matrix<Float> flipweight;
     871           0 :          flipweight=transpose(wt);
     872           0 :          Matrix<Bool> flipchanflag;
     873           0 :          flipchanflag=transpose(chanflag);
     874           0 :          Matrix<Bool> tempoutputflag;
     875             :          InterpolateArray1D<Double,Float>::
     876           0 :          interpolate(weight,tempoutputflag, interpVisFreq_p, visFreq,flipweight,flipchanflag,weightinterp, False, False);
     877           0 :          flipweight.resize();
     878           0 :          flipweight=transpose(weight);
     879           0 :          weight.resize();
     880           0 :          weight.reference(flipweight);
     881           0 :          flipchanflag.resize();
     882           0 :          flipchanflag=transpose(tempoutputflag);
     883           0 :          tempoutputflag.resize();
     884           0 :          tempoutputflag.reference(flipchanflag);
     885             : 
     886             :          // (4) Now, fill these flags back into the flag cube
     887             :          //                 so that they get USED while gridding the PSF (and data)
     888             :          //      Taking the OR of the flags that came out of data-interpolation
     889             :          //                         and weight-interpolation, in case they're different.
     890             :          //      Expanding flags across polarization.  This will destroy any
     891             :          //                          pol-dependent flags for imaging, but msvis::VisImagingWeight
     892             :          //                          uses the OR of flags across polarization anyway
     893             :          //                          so we don't lose anything.
     894             : 
     895           0 :          AlwaysAssert( tempoutputflag.shape()[0]==flag.shape()[1], AipsError);
     896           0 :          AlwaysAssert( tempoutputflag.shape()[1]==flag.shape()[2], AipsError);
     897           0 :          for(uInt pol=0;pol<flag.shape()[0];pol++)
     898           0 :          flag.yzPlane(pol) = tempoutputflag | flag.yzPlane(pol);
     899             : 
     900             :          // Fill the output array of image-channel flags.
     901           0 :          flags.resize(flag.shape());
     902           0 :          flags=0;
     903           0 :          flags(flag)=true;
     904             : 
     905           0 :       return true;
     906         600 :     }
     907             : 
     908         600 :   void FTMachine::getInterpolateArrays(const vi::VisBuffer2& vb,
     909             :                                        Cube<Complex>& data, Cube<Int>& flags){
     910             : 
     911         600 :         Vector<Double> visFreq(vb.getFrequencies(0).nelements());
     912             : 
     913             :       //if(doConversion_p[vb.spectralWindows()[0]]){
     914         600 :       if(freqFrameValid_p){
     915           0 :         convertArray(visFreq, lsrFreq_p);
     916             :       }
     917             :       else{
     918         600 :         convertArray(visFreq, vb.getFrequencies(0));
     919             :       }
     920             : 
     921             : 
     922             : 
     923         600 :       if((imageFreq_p.nelements()==1) || (freqInterpMethod_p== InterpolateArray1D<Double, Complex>::nearestNeighbour)||  (vb.nChannels()==1) ){
     924         600 :         Cube<Bool> modflagCube;
     925         600 :         setSpectralFlag(vb,modflagCube);
     926             : 
     927         600 :                 data.reference(vb.visCubeModel());
     928             :         //flags.resize(vb.flagCube().shape());
     929         600 :         flags.resize(modflagCube.shape());
     930         600 :         flags=0;
     931             :         //flags(vb.flagCube())=true;
     932         600 :         flags(modflagCube)=true;
     933         600 :         interpVisFreq_p.resize();
     934         600 :         interpVisFreq_p=visFreq;
     935         600 :         return;
     936         600 :       }
     937             : 
     938           0 :       data.resize(vb.nCorrelations(), imageFreq_p.nelements(), vb.nRows());
     939           0 :       flags.resize(vb.nCorrelations(), imageFreq_p.nelements(), vb.nRows());
     940           0 :       data.set(Complex(0.0,0.0));
     941           0 :       flags.set(0);
     942             :       //no need to degrid channels that does map over this vb
     943           0 :       Int maxchan=max(chanMap);
     944           0 :       for (uInt k =0 ; k < chanMap.nelements() ; ++k){
     945           0 :         if(chanMap(k)==-1)
     946           0 :         chanMap(k)=maxchan;
     947             :       }
     948           0 :       Int minchan=min(chanMap);
     949           0 :       if(minchan==maxchan)
     950           0 :         minchan=-1;
     951             : 
     952             : 
     953           0 :       for(Int k = 0; k < minchan; ++k)
     954           0 :         flags.xzPlane(k).set(1);
     955             : 
     956           0 :       for(uInt k = maxchan + 1; k < imageFreq_p.nelements(); ++k)
     957           0 :         flags.xzPlane(k).set(1);
     958             : 
     959           0 :       interpVisFreq_p.resize(imageFreq_p.nelements());
     960           0 :       convertArray(interpVisFreq_p, imageFreq_p);
     961           0 :       chanMap.resize(imageFreq_p.nelements());
     962           0 :       indgen(chanMap);
     963         600 :     }
     964             : 
     965         600 :   Bool FTMachine::interpolateFrequencyFromgrid(vi::VisBuffer2& vb,
     966             :                                                Cube<Complex>& data,
     967             :                                                FTMachine::Type type){
     968             : 
     969             :       Cube<Complex> *origdata;
     970         600 :       Vector<Double> visFreq(vb.getFrequencies(0).nelements());
     971             : 
     972             :       //if(doConversion_p[vb.spectralWindows()[0]]){
     973         600 :       if(freqFrameValid_p){
     974           0 :         convertArray(visFreq, lsrFreq_p);
     975             :       }
     976             :       else{
     977         600 :         convertArray(visFreq, vb.getFrequencies(0));
     978             :       }
     979             : 
     980         600 :       if(type==FTMachine::MODEL){
     981         600 :         origdata=const_cast <Cube<Complex>* > (&(vb.visCubeModel()));
     982             :       }
     983           0 :       else if(type==FTMachine::CORRECTED){
     984           0 :         origdata=const_cast<Cube<Complex>* >(&(vb.visCubeCorrected()));
     985             :       }
     986             :       else{
     987           0 :         origdata=const_cast<Cube<Complex>* >(&(vb.visCube()));
     988             :       }
     989             :     //
     990             :     // If visibility data (vb) has only one channel, or the image cube
     991             :     // has only one channel, resort to nearestNeighbour interpolation.
     992             :     // Honour user selection of nearestNeighbour.
     993             :     //
     994             : 
     995         600 :         Double width=fabs(imageFreq_p[1]-imageFreq_p[0])/fabs(visFreq[1]-visFreq[0]);
     996             : 
     997         600 :     if((imageFreq_p.nelements()==1) ||
     998         600 :        (vb.nChannels()==1) ||
     999           0 :        (freqInterpMethod_p== InterpolateArray1D<Double, Complex>::nearestNeighbour) ){
    1000         600 :       interpVisFreq_p=visFreq;
    1001             :       //cerr << "INTERPFROMGRID " << interpVisFreq_p << " vb.nchan " << vb.nChannels() << endl;
    1002         600 :         origdata->reference(data);
    1003         600 :         interpVisFreq_p=visFreq;
    1004         600 :         return false;
    1005             :       }
    1006             : 
    1007             :       //Need to get  new interpolate functions that interpolate explicitly on the 2nd axis
    1008             :       //2 swap of axes needed
    1009           0 :                 Cube<Complex> flipgrid;
    1010           0 :                 flipgrid.resize();
    1011           0 :                 swapyz(flipgrid,data);
    1012           0 :                 Vector<Double> newImFreq;
    1013           0 :                 newImFreq=imageFreq_p;
    1014             : 
    1015             :                 //cerr << "width " << width << endl;
    1016             :                 /* if(((width >2.0) && (freqInterpMethod_p==InterpolateArray1D<Double, Complex>::linear)) ||
    1017             :                    ((width >4.0) && (freqInterpMethod_p !=InterpolateArray1D<Double, Complex>::linear))){*/
    1018           0 :                 if(width > 1.0){
    1019           0 :                         Int newNchan=Int(std::floor(width))*imageFreq_p.nelements();
    1020           0 :                         newImFreq.resize(newNchan);
    1021           0 :                         Double newIncr= (imageFreq_p[1]-imageFreq_p[0])/std::floor(width);
    1022           0 :                         Double newStart=imageFreq_p[0]-(imageFreq_p[1]-imageFreq_p[0])/2.0+newIncr/2.0;
    1023           0 :                         Cube<Complex> newflipgrid(flipgrid.shape()[0], flipgrid.shape()[1], newNchan);
    1024             : 
    1025           0 :                         for (Int k=0; k < newNchan; ++k){
    1026           0 :                                 newImFreq[k]=newStart+k*newIncr;
    1027           0 :                                 Int oldchan=k/Int(std::floor(width));
    1028           0 :                                 newflipgrid.xyPlane(k)=flipgrid.xyPlane(oldchan);
    1029             : 
    1030             :                         }
    1031             :                         //cerr << std::setprecision(12) << "newfreq " << newImFreq << endl;
    1032             :                         //cerr << "oldfreq " << imageFreq_p << endl;
    1033             :                         //InterpolateArray1D<Double,Complex>::
    1034             :         //interpolate(newflipgrid,newImFreq, imageFreq_p, flipgrid, InterpolateArray1D<Double, Complex>::nearestNeighbour);
    1035           0 :                         flipgrid.resize();
    1036           0 :                         flipgrid.reference(newflipgrid);
    1037             : 
    1038           0 :                  }
    1039           0 :       Cube<Complex> flipdata((origdata->shape())(0),(origdata->shape())(2),
    1040           0 :                            (origdata->shape())(1)) ;
    1041           0 :       flipdata.set(Complex(0.0));
    1042             : 
    1043             :       ///TESTOO
    1044             :       //Cube<Bool> inflag(flipgrid.shape());
    1045             :       //inflag.set(False);
    1046             :       //Cube<Bool> outflag(flipdata.shape());
    1047             :       //InterpolateArray1D<Double,Complex>::
    1048             :       //  interpolate(flipdata,outflag,visFreq,newImFreq,flipgrid,inflag,freqInterpMethod_p, False, True);
    1049             : 
    1050             :       //cerr << "OUTFLAG " << anyEQ(True, outflag) << " chanmap " << chanMap << endl;
    1051             :       /////End TESTOO
    1052             :       InterpolateArray1D<Double,Complex>::
    1053           0 :         interpolate(flipdata,visFreq, newImFreq, flipgrid,freqInterpMethod_p);
    1054             : 
    1055             : 
    1056             : 
    1057           0 :       Cube<Bool>  copyOfFlag;
    1058             :       //Vector<Int> mychanmap=multiChanMap_p[vb.spectralWindows()[0]];
    1059           0 :       matchChannel(vb);
    1060           0 :       copyOfFlag.assign(vb.flagCube());
    1061           0 :       for (uInt k=0; k< chanMap.nelements(); ++ k)
    1062           0 :         if(chanMap(k) == -1)
    1063           0 :           copyOfFlag.xzPlane(k).set(true);
    1064           0 :       flipgrid.resize();
    1065           0 :       swapyz(flipgrid, copyOfFlag, flipdata);
    1066             :       //swapyz(flipgrid,flipdata);
    1067           0 :       vb.setVisCubeModel(flipgrid);
    1068             : 
    1069           0 :       return true;
    1070         600 :     }
    1071             : 
    1072             : 
    1073           0 :   void FTMachine::girarUVW(Matrix<Double>& uvw, Vector<Double>& dphase,
    1074             :                          const vi::VisBuffer2& vb)
    1075             : {
    1076             : 
    1077             : 
    1078             : 
    1079             :     //the uvw rotation is done for common tangent reprojection or if the
    1080             :     //image center is different from the phasecenter
    1081             :     // UVrotation is false only if field never changes
    1082           0 :   if(lastMSId_p != vb.msId())
    1083           0 :     romscol_p=new MSColumns(vb.ms());
    1084           0 :    if((vb.fieldId()(0)!=lastFieldId_p) || (vb.msId()!=lastMSId_p)){
    1085           0 :       doUVWRotation_p=true;
    1086             :    }
    1087             :    else{
    1088             :      //if above failed it still can be changing if   polynome phasecenter or ephem
    1089             : 
    1090           0 :      if( (vb.subtableColumns().field().numPoly()(lastFieldId_p) >0) ||  (! (vb.subtableColumns().field().ephemerisId().isNull()) && (vb.subtableColumns().field().ephemerisId()(lastFieldId_p) > -1)))
    1091           0 :        doUVWRotation_p=True;
    1092             :    }
    1093           0 :    if(doUVWRotation_p ||  fixMovingSource_p){
    1094             : 
    1095           0 :       mFrame_p.epoch() != 0 ?
    1096           0 :         mFrame_p.resetEpoch(MEpoch(Quantity(vb.time()(0), "s"))):
    1097           0 :         mFrame_p.set(mLocation_p, MEpoch(Quantity(vb.time()(0), "s"), (romscol_p->timeMeas())(0).getRef()));
    1098             :       MDirection::Types outType;
    1099           0 :       MDirection::getType(outType, mImage_p.getRefString());
    1100           0 :       MDirection phasecenter=MDirection::Convert(vbutil_p->getPhaseCenter(vb, phaseCenterTime_p), MDirection::Ref(outType, mFrame_p))();
    1101           0 :       MDirection inFieldPhaseCenter=phasecenter;
    1102             : 
    1103           0 :       if(fixMovingSource_p){
    1104             : 
    1105             :       //First convert to HA-DEC or AZEL for parallax correction
    1106           0 :         MDirection::Ref outref1(MDirection::AZEL, mFrame_p);
    1107           0 :         MDirection tmphadec;
    1108           0 :         if(upcase(movingDir_p.getRefString()).contains("APP")){
    1109           0 :           tmphadec=MDirection::Convert((vbutil_p->getEphemDir(vb, phaseCenterTime_p)), outref1)();
    1110             :         }
    1111             :         else{
    1112           0 :           tmphadec=MDirection::Convert(movingDir_p, outref1)();
    1113             :         }
    1114           0 :         MDirection::Ref outref(mImage_p.getRef().getType(), mFrame_p);
    1115           0 :         MDirection sourcenow=MDirection::Convert(tmphadec, outref)();
    1116             :         //cerr << "Rotating to fixed moving source " << MVDirection(phasecenter.getAngle()-firstMovingDir_p.getAngle()+sourcenow.getAngle()) << endl;
    1117             :         //phasecenter.set(MVDirection(phasecenter.getAngle()+firstMovingDir_p.getAngle()-sourcenow.getAngle()));
    1118           0 :          movingDirShift_p=MVDirection(sourcenow.getAngle()-firstMovingDir_p.getAngle());
    1119             :          // cerr << "shift " << movingDirShift_p.getAngle() << endl;
    1120           0 :         inFieldPhaseCenter.shift(movingDirShift_p, False);
    1121           0 :     }
    1122             : 
    1123             : 
    1124             :       // Set up the UVWMachine only if the field id has changed. If
    1125             :       // the tangent plane is specified then we need a UVWMachine that
    1126             :       // will reproject to that plane iso the image plane
    1127           0 :       if(doUVWRotation_p || fixMovingSource_p) {
    1128             : 
    1129           0 :         String observatory=(vb.subtableColumns().observation()).telescopeName()(0);
    1130           0 :         if(uvwMachine_p) delete uvwMachine_p; uvwMachine_p=0;
    1131           0 :         if(observatory.contains("ATCA") || observatory.contains("WSRT")){
    1132             :                 //Tangent specified is being wrongly used...it should be for a
    1133             :                 //Use the safest way  for now.
    1134           0 :           uvwMachine_p=new UVWMachine(inFieldPhaseCenter, vbutil_p->getPhaseCenter(vb, phaseCenterTime_p), mFrame_p,
    1135           0 :                                         true, false);
    1136           0 :             phaseShifter_p=new UVWMachine(mImage_p, phasecenter, mFrame_p,
    1137           0 :                                         true, false);
    1138             :         }
    1139             :         else{
    1140           0 :           uvwMachine_p=new UVWMachine(inFieldPhaseCenter, vbutil_p->getPhaseCenter(vb, phaseCenterTime_p),  mFrame_p,
    1141           0 :                                       false, false);
    1142           0 :           phaseShifter_p=new UVWMachine(mImage_p, phasecenter,  mFrame_p,
    1143           0 :                                       false, false);
    1144             :         }
    1145           0 :       }
    1146             : 
    1147           0 :       lastFieldId_p=vb.fieldId()(0);
    1148           0 :         lastMSId_p=vb.msId();
    1149             : 
    1150             : 
    1151           0 :       AlwaysAssert(uvwMachine_p, AipsError);
    1152             : 
    1153             :       // Always force a recalculation
    1154           0 :       uvwMachine_p->reCalculate();
    1155           0 :       phaseShifter_p->reCalculate();
    1156             : 
    1157             :       // Now do the conversions
    1158           0 :       uInt nrows=dphase.nelements();
    1159           0 :       Vector<Double> thisRow(3);
    1160           0 :       thisRow=0.0;
    1161             :       //CoordinateSystem csys=image->coordinates();
    1162             :       //DirectionCoordinate dc=csys.directionCoordinate(0);
    1163             :       //Vector<Double> thePix(2);
    1164             :       //dc.toPixel(thePix, phasecenter);
    1165             :       //cerr << "field id " << vb.fieldId() << "  the Pix " << thePix << endl;
    1166             :       //Vector<Float> scale(2);
    1167             :       //scale(0)=dc.increment()(0);
    1168             :       //scale(1)=dc.increment()(1);
    1169           0 :       for (uInt irow=0; irow<nrows;++irow) {
    1170           0 :         thisRow.assign(uvw.column(irow));
    1171             :         //cerr << " uvw " << thisRow ;
    1172             :         // This is for frame change
    1173           0 :         uvwMachine_p->convertUVW(dphase(irow), thisRow);
    1174             :         // This is for correlator phase center change
    1175           0 :         MVPosition rotphase=phaseShifter_p->rotationPhase() ;
    1176             :         //cerr << " rotPhase " <<  rotphase << " oldphase "<<  rotphase*(uvw.column(irow))  << " newphase " << (rotphase)*thisRow ;
    1177             :         //      cerr << " phase " << dphase(irow) << " new uvw " << uvw.column(irow);
    1178             :         //dphase(irow)+= (thePix(0)-nx/2.0)*thisRow(0)*scale(0)+(thePix(1)-ny/2.0)*thisRow(1)*scale(1);
    1179             :         //Double pixphase=(thePix(0)-nx/2.0)*uvw.column(irow)(0)*scale(0)+(thePix(1)-ny/2.0)*uvw.column(irow)(1)*scale(1);
    1180             :         //Double pixphase2=(thePix(0)-nx/2.0)*thisRow(0)*scale(0)+(thePix(1)-ny/2.0)*thisRow(1)*scale(1);
    1181             :         //cerr << " pixphase " <<  pixphase <<  " pixphase2 " << pixphase2<< endl;
    1182             :         //dphase(irow)=pixphase;
    1183           0 :         RotMatrix rotMat=phaseShifter_p->rotationUVW();
    1184           0 :         uvw.column(irow)(0)=thisRow(0)*rotMat(0,0)+thisRow(1)*rotMat(1,0);
    1185           0 :         uvw.column(irow)(1)=thisRow(1)*rotMat(1,1)+thisRow(0)*rotMat(0,1);
    1186           0 :         uvw.column(irow)(2)=thisRow(0)*rotMat(0,2)+thisRow(1)*rotMat(1,2)+thisRow(2)*rotMat(2,2);
    1187           0 :         dphase(irow)+= rotphase(0)*uvw.column(irow)(0)+rotphase(1)*uvw.column(irow)(1);
    1188           0 :       }
    1189             : 
    1190             : 
    1191           0 :     }
    1192           0 : }
    1193             : 
    1194             : 
    1195        1200 :   void FTMachine::rotateUVW(Matrix<Double>& uvw, Vector<Double>& dphase,
    1196             :                             const vi::VisBuffer2& vb)
    1197             :     {
    1198             : 
    1199        1200 :       if(lastMSId_p != vb.msId())
    1200           0 :         romscol_p=new MSColumns(vb.ms());
    1201             :       //the uvw rotation is done for common tangent reprojection or if the
    1202             :       //image center is different from the phasecenter
    1203             :       // UVrotation is false only if field never changes
    1204             : 
    1205        1200 :       if((vb.fieldId()(0)!=lastFieldId_p) || (vb.msId()!=lastMSId_p)){
    1206           6 :         doUVWRotation_p=true;
    1207             : 
    1208             :       }
    1209             :       else{
    1210             :         //if above failed it still can be changing if   polynome phasecenter or ephem
    1211        1194 :         if( (vb.subtableColumns().field().numPoly()(lastFieldId_p) >0) ||  (! (vb.subtableColumns().field().ephemerisId().isNull()) &&(vb.subtableColumns().field().ephemerisId()(lastFieldId_p) > -1)))
    1212           0 :           doUVWRotation_p=True;
    1213             : 
    1214             :       }
    1215        1200 :       if(doUVWRotation_p || tangentSpecified_p || fixMovingSource_p){
    1216        1200 :         ok();
    1217             : 
    1218        1200 :         mFrame_p.epoch() != 0 ?
    1219        2400 :           mFrame_p.resetEpoch(MEpoch(Quantity(vb.time()(0), "s"))):
    1220             : 
    1221        1200 :           mFrame_p.set(mLocation_p, MEpoch(Quantity(vb.time()(0), "s"), (romscol_p->timeMeas())(0).getRef()));
    1222             : 
    1223        1200 :         MDirection phasecenter=mImage_p;
    1224        1200 :         if(fixMovingSource_p){
    1225             : 
    1226             :           //First convert to HA-DEC or AZEL for parallax correction
    1227           0 :           MDirection::Ref outref1(MDirection::AZEL, mFrame_p);
    1228           0 :           MDirection tmphadec;
    1229           0 :           if(upcase(movingDir_p.getRefString()).contains("APP")){
    1230           0 :             tmphadec=MDirection::Convert((vbutil_p->getEphemDir(vb, phaseCenterTime_p)), outref1)();
    1231             :           }
    1232             :           else{
    1233           0 :             tmphadec=MDirection::Convert(movingDir_p, outref1)();
    1234             :           }
    1235             :           ////TESTOO waiting for CAS-11060
    1236             :           //MDirection tmphadec=MDirection::Convert((vbutil_p->getPhaseCenter(vb, phaseCenterTime_p)), outref1)();
    1237             :           /////////
    1238           0 :           MDirection::Ref outref(mImage_p.getRef().getType(), mFrame_p);
    1239           0 :           MDirection sourcenow=MDirection::Convert(tmphadec, outref)();
    1240             :         //cerr << "Rotating to fixed moving source " << MVDirection(phasecenter.getAngle()-firstMovingDir_p.getAngle()+sourcenow.getAngle()) << endl;
    1241             :         //phasecenter.set(MVDirection(phasecenter.getAngle()+firstMovingDir_p.getAngle()-sourcenow.getAngle()));
    1242           0 :           movingDirShift_p=MVDirection(sourcenow.getAngle()-firstMovingDir_p.getAngle());
    1243           0 :           phasecenter.shift(movingDirShift_p, False);
    1244             :           //cerr    << sourcenow.toString() <<"  "<<(vbutil_p->getPhaseCenter(vb, phaseCenterTime_p)).toString() <<  " difference " << firstMovingDir_p.getAngle() - sourcenow.getAngle() << endl;
    1245           0 :       }
    1246             : 
    1247             : 
    1248             :         // Set up the UVWMachine only if the field id has changed. If
    1249             :         // the tangent plane is specified then we need a UVWMachine that
    1250             :         // will reproject to that plane iso the image plane
    1251        1200 :         if(doUVWRotation_p || fixMovingSource_p) {
    1252             : 
    1253        1200 :           String observatory=(vb.subtableColumns().observation()).telescopeName()(0);
    1254        1200 :         if(uvwMachine_p) delete uvwMachine_p; uvwMachine_p=0;
    1255        1200 :         if(observatory.contains("ATCA") || observatory.contains("WSRT")){
    1256             :                 //Tangent specified is being wrongly used...it should be for a
    1257             :                 //Use the safest way  for now.
    1258           0 :           uvwMachine_p=new UVWMachine(phasecenter, vbutil_p->getPhaseCenter(vb, phaseCenterTime_p), mFrame_p,
    1259           0 :                                         true, false);
    1260             :         }
    1261             :         else{
    1262        2400 :           uvwMachine_p=new UVWMachine(phasecenter, vbutil_p->getPhaseCenter(vb, phaseCenterTime_p), mFrame_p,
    1263        1200 :                                         false,tangentSpecified_p);
    1264             :             }
    1265        1200 :        }
    1266             : 
    1267        1200 :         lastFieldId_p=vb.fieldId()(0);
    1268        1200 :         lastMSId_p=vb.msId();
    1269             : 
    1270             : 
    1271        1200 :         AlwaysAssert(uvwMachine_p, AipsError);
    1272             : 
    1273             :         // Always force a recalculation
    1274        1200 :         uvwMachine_p->reCalculate();
    1275             : 
    1276             :         // Now do the conversions
    1277        1200 :         uInt nrows=dphase.nelements();
    1278        1200 :         Vector<Double> thisRow(3);
    1279        1200 :         thisRow=0.0;
    1280             :         uInt irow;
    1281             :         //#pragma omp parallel default(shared) private(irow,thisRow)
    1282             :         {
    1283             :         //#pragma omp for
    1284      422400 :           for (irow=0; irow<nrows;++irow) {
    1285      421200 :             thisRow.reference(uvw.column(irow));
    1286      421200 :             convUVW(dphase(irow), thisRow);
    1287             :           }
    1288             : 
    1289             :         }//end pragma
    1290        1200 :       }
    1291        1200 :     }
    1292      421200 :   void FTMachine::convUVW(Double& dphase, Vector<Double>& thisrow){
    1293             :     //for (uInt i=0;i<3;i++) thisRow(i)=uvw(i,row);
    1294      421200 :     uvwMachine_p->convertUVW(dphase, thisrow);
    1295             :     //for (uint i=0;i<3;i++) uvw(i,row)=thisRow(i);
    1296             : 
    1297      421200 :   }
    1298             : 
    1299             : 
    1300       70200 :   void FTMachine::locateuvw(const Double*& uvw, const Double*& dphase,
    1301             :                             const Double*& freq, const Int& nvchan,
    1302             :                             const Double*& scale, const Double*& offset,  const Int& sampling, Int*& loc, Int*& off, Complex*& phasor, const Int& row, const bool& doW){
    1303             : 
    1304       70200 :     Int rowoff=row*nvchan;
    1305             :     Double phase;
    1306             :     Double pos;
    1307       70200 :     Int nel= doW ? 3 : 2;
    1308     7090200 :     for (Int f=0; f<nvchan; ++f){
    1309    21060000 :       for (Int k=0; k <2; ++k){
    1310    14040000 :         pos=(scale[k])*uvw[3*row+k]*(freq[f])/C::c+((offset[k])+1.0);
    1311    14040000 :         loc[(rowoff+f)*nel+k]=std::lround(pos);
    1312    14040000 :         off[(rowoff+f)*nel+k]=std::lround((Double(loc[(rowoff+f)*nel+k])-pos)*Double(sampling));
    1313             :         //off[(rowoff+f)*2+k]=(loc[(rowoff+f)*2+k]-pos(k))*sampling;
    1314             :       }
    1315     7020000 :       phase=-Double(2.0)*C::pi*dphase[row]*(freq[f])/C::c;
    1316     7020000 :       phasor[rowoff+f]=Complex(cos(phase), sin(phase));
    1317             : 
    1318             :       ///This is for W-Projection
    1319     7020000 :       if(doW){
    1320           0 :         pos=sqrt(fabs(scale[2]*uvw[3*row+2]*(freq[f])/C::c))+offset[2]+1.0;
    1321           0 :         loc[(rowoff+f)*nel+2]=std::lround(pos);
    1322           0 :         off[(rowoff+f)*nel+2]=0;
    1323             :       }
    1324             :     }
    1325             : 
    1326             : 
    1327             : 
    1328             : 
    1329       70200 :   }
    1330             : 
    1331           0 :   void FTMachine::setnumthreads(Int num){
    1332           0 :     numthreads_p=num;
    1333           0 :   }
    1334           0 :   Int FTMachine::getnumthreads(){
    1335           0 :     return numthreads_p;
    1336             :   }
    1337             : 
    1338             :   //
    1339             :   // Refocus the array on a point at finite distance
    1340             :   //
    1341             :     // Refocus the array on a point at finite distance
    1342             :     //
    1343        1200 :     void FTMachine::refocus(Matrix<Double>& uvw, const Vector<Int>& ant1,
    1344             :                           const Vector<Int>& ant2,
    1345             :                           Vector<Double>& dphase, const vi::VisBuffer2& vb)
    1346             :     {
    1347             : 
    1348        1200 :       ok();
    1349             : 
    1350        1200 :       if(abs(distance_p)>0.0) {
    1351             : 
    1352           0 :         nAntenna_p=max(vb.antenna2())+1;
    1353             : 
    1354             :         // Positions of antennas
    1355           0 :         Matrix<Double> antPos(3,nAntenna_p);
    1356           0 :         antPos=0.0;
    1357           0 :         Vector<Int> nAntPos(nAntenna_p);
    1358           0 :         nAntPos=0;
    1359             : 
    1360           0 :         uInt aref = min(ant1);
    1361             : 
    1362             :         // Now find the antenna locations: for this we just reference to a common
    1363             :         // point. We ignore the time variation within this buffer.
    1364           0 :         uInt nrows=dphase.nelements();
    1365           0 :         for (uInt row=0;row<nrows;row++) {
    1366           0 :         uInt a1=ant1(row);
    1367           0 :         uInt a2=ant2(row);
    1368           0 :         for(uInt dim=0;dim<3;dim++) {
    1369           0 :           antPos(dim, a1)+=uvw(dim, row);
    1370           0 :           antPos(dim, a2)-=uvw(dim, row);
    1371             :         }
    1372           0 :         nAntPos(a1)+=1;
    1373           0 :         nAntPos(a2)+=1;
    1374             :         }
    1375             : 
    1376             :         // Now remove the reference location
    1377           0 :         Vector<Double> center(3);
    1378           0 :         for(uInt dim=0;dim<3;dim++) {
    1379           0 :         center(dim) = antPos(dim,aref)/nAntPos(aref);
    1380             :         }
    1381             : 
    1382             :         // Now normalize
    1383           0 :         for (uInt ant=0; ant<nAntenna_p; ant++) {
    1384           0 :         if(nAntPos(ant)>0) {
    1385           0 :           for(uInt dim=0;dim<3;dim++) {
    1386           0 :             antPos(dim,ant)/=nAntPos(ant);
    1387           0 :             antPos(dim,ant)-=center(dim);
    1388             :           }
    1389             :         }
    1390             :         }
    1391             : 
    1392             :         // Now calculate the offset needed to focus the array,
    1393             :         // including the w term. This must have the correct asymptotic
    1394             :         // form so that at infinity no net change occurs
    1395           0 :         for (uInt row=0;row<nrows;row++) {
    1396           0 :         uInt a1=ant1(row);
    1397           0 :         uInt a2=ant2(row);
    1398             : 
    1399           0 :         Double d1=distance_p*distance_p-2*distance_p*antPos(2,a1);
    1400           0 :         Double d2=distance_p*distance_p-2*distance_p*antPos(2,a2);
    1401           0 :         for(uInt dim=0;dim<3;dim++) {
    1402           0 :           d1+=antPos(dim,a1)*antPos(dim,a1);
    1403           0 :           d2+=antPos(dim,a2)*antPos(dim,a2);
    1404             :         }
    1405           0 :         d1=sqrt(d1);
    1406           0 :         d2=sqrt(d2);
    1407           0 :         for(uInt dim=0;dim<2;dim++) {
    1408           0 :           dphase(row)-=(antPos(dim,a1)*antPos(dim,a1)-antPos(dim,a2)*antPos(dim,a2))/(2*distance_p);
    1409             :         }
    1410           0 :         uvw(0,row)=distance_p*(antPos(0,a1)/d1-antPos(0,a2)/d2);
    1411           0 :         uvw(1,row)=distance_p*(antPos(1,a1)/d1-antPos(1,a2)/d2);
    1412           0 :         uvw(2,row)=distance_p*(antPos(2,a1)/d1-antPos(2,a2)/d2)+dphase(row);
    1413             :         }
    1414           0 :       }
    1415        1200 :     }
    1416             : 
    1417           0 :   void FTMachine::ok() {
    1418           0 :     AlwaysAssert(image, AipsError);
    1419           0 :     AlwaysAssert(uvwMachine_p, AipsError);
    1420           0 :   }
    1421             : 
    1422           0 :   Bool FTMachine::toRecord(String& error, RecordInterface& outRecord,
    1423             :                            Bool withImage, const String diskimage) {
    1424             :     // Save the FTMachine to a Record
    1425             :     //
    1426           0 :     outRecord.define("name", this->name());
    1427           0 :     if(withImage){
    1428           0 :       if(image==nullptr)
    1429           0 :         throw(AipsError("Programmer error: saving to record without proper initialization"));
    1430           0 :       CoordinateSystem cs=image->coordinates();
    1431           0 :       DirectionCoordinate dircoord=cs.directionCoordinate(cs.findCoordinate(Coordinate::DIRECTION));
    1432           0 :       dircoord.setReferenceValue(mImage_p.getAngle().getValue());
    1433           0 :       if(diskimage != ""){
    1434             :         try{
    1435           0 :           PagedImage<Complex> imCopy(TiledShape(toVis_p ? griddedData.shape(): image->shape()), image->coordinates(), diskimage);
    1436           0 :           toVis_p ? imCopy.put(griddedData) : imCopy.copyData(*image);
    1437           0 :           ImageUtilities::copyMiscellaneous(imCopy, *image);
    1438           0 :           Vector<Double> pixcen(2);
    1439           0 :           pixcen(0)=Double(imCopy.shape()(0)/2); pixcen(1)=Double(imCopy.shape()(1)/2);
    1440           0 :           dircoord.setReferencePixel(pixcen);
    1441           0 :           cs.replaceCoordinate(dircoord, cs.findCoordinate(Coordinate::DIRECTION));
    1442           0 :           imCopy.setCoordinateInfo(cs);
    1443           0 :         }
    1444           0 :         catch(...){
    1445           0 :           throw(AipsError(String("Failed to save model image "+diskimage+String(" to disk"))));
    1446           0 :         }
    1447           0 :         outRecord.define("diskimage", diskimage);
    1448             : 
    1449             :       }
    1450             :       else{
    1451           0 :         Record imrec;
    1452           0 :         Vector<Double> pixcen(2);
    1453           0 :         pixcen(0)=Double(griddedData.shape()(0)/2); pixcen(1)=Double(griddedData.shape()(1)/2);
    1454           0 :         dircoord.setReferencePixel(pixcen);
    1455           0 :         cs.replaceCoordinate(dircoord, cs.findCoordinate(Coordinate::DIRECTION));
    1456           0 :         TempImage<Complex> imCopy(griddedData.shape(), cs);
    1457           0 :         imCopy.put(griddedData) ;
    1458           0 :         ImageUtilities::copyMiscellaneous(imCopy, *image);
    1459           0 :         if(imCopy.toRecord(error, imrec))
    1460           0 :           outRecord.defineRecord("image", imrec);
    1461           0 :       }
    1462           0 :     }
    1463           0 :     outRecord.define("nantenna", nAntenna_p);
    1464           0 :     outRecord.define("distance", distance_p);
    1465           0 :     outRecord.define("lastfieldid", lastFieldId_p);
    1466           0 :     outRecord.define("lastmsid", lastMSId_p);
    1467           0 :     outRecord.define("tangentspecified", tangentSpecified_p);
    1468           0 :     saveMeasure(outRecord, String("mtangent_rec"), error, mTangent_p);
    1469           0 :     saveMeasure(outRecord, "mimage_rec", error, mImage_p);
    1470             :     //mFrame_p not necessary to save as it is generated from mLocation_p
    1471           0 :     outRecord.define("nx", nx);
    1472           0 :     outRecord.define("ny", ny);
    1473           0 :     outRecord.define("npol", npol);
    1474           0 :     outRecord.define("nchan", nchan);
    1475           0 :     outRecord.define("nvischan", nvischan);
    1476           0 :     outRecord.define("nvispol", nvispol);
    1477             :     //no need to save uvwMachine_p
    1478           0 :     outRecord.define("douvwrotation", doUVWRotation_p);
    1479           0 :     outRecord.define("freqinterpmethod", static_cast<Int>(freqInterpMethod_p));
    1480           0 :     outRecord.define("spwchanselflag", spwChanSelFlag_p);
    1481           0 :     outRecord.define("freqframevalid", freqFrameValid_p);
    1482             :     //outRecord.define("selectedspw", selectedSpw_p);
    1483           0 :     outRecord.define("imagefreq", imageFreq_p);
    1484           0 :     outRecord.define("lsrfreq", lsrFreq_p);
    1485           0 :     outRecord.define("interpvisfreq", interpVisFreq_p);
    1486           0 :     Record multichmaprec;
    1487             :     //for (uInt k=0; k < multiChanMap_p.nelements(); ++k)
    1488             :     //  multichmaprec.define(k, multiChanMap_p[k]);
    1489             :     //outRecord.defineRecord("multichanmaprec", multichmaprec);
    1490           0 :     outRecord.define("chanmap", chanMap);
    1491           0 :     outRecord.define("polmap", polMap);
    1492           0 :     outRecord.define("nvischanmulti", nVisChan_p);
    1493             :     //save moving source related variables
    1494           0 :     storeMovingSourceState(error, outRecord);
    1495             :     //outRecord.define("doconversion", doConversion_p);
    1496           0 :     outRecord.define("pointingdircol", pointingDirCol_p);
    1497           0 :     outRecord.define("usedoublegrid", useDoubleGrid_p);
    1498           0 :     outRecord.define("cfstokes", cfStokes_p);
    1499           0 :     outRecord.define("polinuse", polInUse_p);
    1500           0 :     outRecord.define("tovis", toVis_p);
    1501           0 :     outRecord.define("sumweight", sumWeight);
    1502           0 :     outRecord.define("numthreads", numthreads_p);
    1503           0 :     outRecord.define("phasecentertime", phaseCenterTime_p);
    1504             :     //Need to serialized sj_p...the user has to set the sj_p after recovering from record
    1505           0 :     return true;
    1506           0 :   };
    1507             : 
    1508           0 :   Bool FTMachine::saveMeasure(RecordInterface& rec, const String& name, String& err, const Measure& meas){
    1509           0 :     Record tmprec;
    1510           0 :     MeasureHolder mh(meas);
    1511           0 :     if(mh.toRecord(err, tmprec)){
    1512           0 :       rec.defineRecord(name, tmprec);
    1513           0 :       return true;
    1514             :     }
    1515           0 :     return false;
    1516           0 :   }
    1517             : 
    1518           0 :   Bool FTMachine::fromRecord(String& error,
    1519             :                              const RecordInterface& inRecord
    1520             :                              ) {
    1521             :     // Restore an FTMachine from a Record
    1522             :     //
    1523           0 :     uvwMachine_p=0; //when null it is reconstructed from mImage_p and mFrame_p
    1524             :     //mFrame_p is not necessary as it is generated in initMaps from mLocation_p
    1525           0 :     inRecord.get("nx", nx);
    1526           0 :     inRecord.get("ny", ny);
    1527           0 :     inRecord.get("npol", npol);
    1528           0 :     inRecord.get("nchan", nchan);
    1529           0 :     inRecord.get("nvischan", nvischan);
    1530           0 :     inRecord.get("nvispol", nvispol);
    1531           0 :     cmplxImage_p=NULL;
    1532           0 :     inRecord.get("tovis", toVis_p);
    1533           0 :     if(inRecord.isDefined("image")){
    1534           0 :       cmplxImage_p=new TempImage<Complex>();
    1535           0 :       image=&(*cmplxImage_p);
    1536             : 
    1537           0 :       const Record rec=inRecord.asRecord("image");
    1538           0 :       if(!cmplxImage_p->fromRecord(error, rec))
    1539           0 :         return false;
    1540             : 
    1541           0 :     }
    1542           0 :     else if(inRecord.isDefined("diskimage")){
    1543           0 :       String theDiskImage;
    1544           0 :       inRecord.get("diskimage", theDiskImage);
    1545             :       try{
    1546           0 :         File eldir(theDiskImage);
    1547           0 :         if(! eldir.exists()){
    1548           0 :           String subPathname[30];
    1549           0 :           String sep = "/";
    1550           0 :           uInt nw = split(theDiskImage, subPathname, 20, sep);
    1551           0 :           String theposs=(subPathname[nw-1]);
    1552           0 :           Bool isExistant=File(theposs).exists();
    1553           0 :           if(isExistant)
    1554           0 :             theDiskImage=theposs;
    1555           0 :           for (uInt i=nw-2 ; i>0; --i){
    1556           0 :             theposs=subPathname[i]+"/"+theposs;
    1557           0 :             File newEldir(theposs);
    1558           0 :             if(newEldir.exists()){
    1559           0 :               isExistant=true;
    1560           0 :               theDiskImage=theposs;
    1561             :             }
    1562           0 :           }
    1563           0 :           if(!isExistant)
    1564           0 :             throw(AipsError("Could not locate mage"));
    1565           0 :         }
    1566           0 :         cmplxImage_p=new PagedImage<Complex> (theDiskImage);
    1567           0 :         image=&(*cmplxImage_p);
    1568           0 :       }
    1569           0 :       catch(...){
    1570           0 :         throw(AipsError(String("Failure to load ")+theDiskImage+String(" image from disk")));
    1571           0 :       }
    1572           0 :     }
    1573           0 :     if(toVis_p && !cmplxImage_p.null()) {
    1574           0 :         griddedData.resize(image->shape());
    1575           0 :         griddedData=image->get();
    1576             :     }
    1577           0 :     else if(!toVis_p){
    1578           0 :       IPosition gridShape(4, nx, ny, npol, nchan);
    1579           0 :       griddedData.resize(gridShape);
    1580           0 :       griddedData=Complex(0.0);
    1581           0 :     }
    1582             : 
    1583           0 :     nAntenna_p=inRecord.asuInt("nantenna");
    1584           0 :     distance_p=inRecord.asDouble("distance");
    1585           0 :     lastFieldId_p=inRecord.asInt("lastfieldid");
    1586           0 :     lastMSId_p=inRecord.asInt("lastmsid");
    1587           0 :     inRecord.get("tangentspecified", tangentSpecified_p);
    1588           0 :     { const Record rec=inRecord.asRecord("mtangent_rec");
    1589           0 :       MeasureHolder mh;
    1590           0 :       if(!mh.fromRecord(error, rec))
    1591           0 :         return false;
    1592           0 :       mTangent_p=mh.asMDirection();
    1593           0 :     }
    1594           0 :     { const Record rec=inRecord.asRecord("mimage_rec");
    1595           0 :       MeasureHolder mh;
    1596           0 :       if(!mh.fromRecord(error, rec))
    1597           0 :         return false;
    1598           0 :       mImage_p=mh.asMDirection();
    1599           0 :     }
    1600             : 
    1601             : 
    1602             : 
    1603           0 :     inRecord.get("douvwrotation", doUVWRotation_p);
    1604             : 
    1605             :     //inRecord.get("spwchanselflag", spwChanSelFlag_p);
    1606             :     //We won't respect the chanselflag as the vister may have different selections
    1607           0 :     spwChanSelFlag_p.resize();
    1608           0 :     inRecord.get("freqframevalid", freqFrameValid_p);
    1609             :     //inRecord.get("selectedspw", selectedSpw_p);
    1610           0 :     inRecord.get("imagefreq", imageFreq_p);
    1611           0 :     inRecord.get("lsrfreq", lsrFreq_p);
    1612           0 :     inRecord.get("interpvisfreq", interpVisFreq_p);
    1613             :     //const Record multichmaprec=inRecord.asRecord("multichanmaprec");
    1614             :     //multiChanMap_p.resize(multichmaprec.nfields(), true, false);
    1615             :     //for (uInt k=0; k < multichmaprec.nfields(); ++k)
    1616             :     //  multichmaprec.get(k, multiChanMap_p[k]);
    1617           0 :     inRecord.get("chanmap", chanMap);
    1618           0 :     inRecord.get("polmap", polMap);
    1619           0 :     inRecord.get("nvischanmulti", nVisChan_p);
    1620             :     //inRecord.get("doconversion", doConversion_p);
    1621           0 :     inRecord.get("pointingdircol", pointingDirCol_p);
    1622             : 
    1623             : 
    1624           0 :     inRecord.get("usedoublegrid", useDoubleGrid_p);
    1625           0 :     inRecord.get("cfstokes", cfStokes_p);
    1626           0 :     inRecord.get("polinuse", polInUse_p);
    1627             : 
    1628             : 
    1629           0 :     inRecord.get("sumweight", sumWeight);
    1630           0 :     if(toVis_p){
    1631           0 :       freqInterpMethod_p=InterpolateArray1D<Double, Complex>::nearestNeighbour;
    1632             :     }
    1633             :     else{
    1634             :      Int tmpInt;
    1635           0 :       inRecord.get("freqinterpmethod", tmpInt);
    1636           0 :       freqInterpMethod_p=static_cast<InterpolateArray1D<Double, Complex >::InterpolationMethod>(tmpInt);
    1637             :     }
    1638           0 :     inRecord.get("numthreads", numthreads_p);
    1639           0 :     inRecord.get("phasecentertime", phaseCenterTime_p);
    1640             :     ///No need to store this...recalculate thread partion because environment
    1641             :     ///may have changed.
    1642           0 :     doneThreadPartition_p=-1;
    1643           0 :     vbutil_p=nullptr;
    1644           0 :     briggsWeightor_p=nullptr;
    1645           0 :     ft_p=FFT2D(true);
    1646           0 :     if(!recoverMovingSourceState(error, inRecord))
    1647           0 :       return False;
    1648           0 :     return true;
    1649             :   };
    1650           0 :   Bool FTMachine::storeMovingSourceState(String& error, RecordInterface& outRecord){
    1651             : 
    1652           0 :     Bool retval=True;
    1653           0 :     retval=retval && saveMeasure(outRecord, "mlocation_rec", error, mLocation_p);
    1654           0 :     spectralCoord_p.save(outRecord, "spectralcoord");
    1655           0 :     retval=retval && saveMeasure(outRecord, "movingdir_rec", error, movingDir_p);
    1656           0 :     outRecord.define("fixmovingsource", fixMovingSource_p);
    1657           0 :     retval=retval && saveMeasure(outRecord, "firstmovingdir_rec", error, firstMovingDir_p);
    1658           0 :     movingDirShift_p=MVDirection(0.0);
    1659           0 :     if( mFrame_p.comet()){
    1660           0 :       String ephemTab=MeasComet(*(mFrame_p.comet())).getTablePath();
    1661           0 :       outRecord.define("ephemeristable",ephemTab);
    1662           0 :     }
    1663           0 :     return retval;
    1664             :   }
    1665           0 :   Bool FTMachine::recoverMovingSourceState(String& error, const RecordInterface& inRecord){
    1666           0 :     Bool retval=True;
    1667           0 :     inRecord.get("fixmovingsource", fixMovingSource_p);
    1668           0 :     { const Record rec=inRecord.asRecord("firstmovingdir_rec");
    1669           0 :       MeasureHolder mh;
    1670           0 :       if(!mh.fromRecord(error, rec))
    1671           0 :         return false;
    1672           0 :       firstMovingDir_p=mh.asMDirection();
    1673           0 :     }
    1674           0 :     { const Record rec=inRecord.asRecord("movingdir_rec");
    1675           0 :       MeasureHolder mh;
    1676           0 :       if(!mh.fromRecord(error, rec))
    1677           0 :         return false;
    1678           0 :       movingDir_p=mh.asMDirection();
    1679           0 :     }
    1680           0 :      { const Record rec=inRecord.asRecord("mlocation_rec");
    1681           0 :       MeasureHolder mh;
    1682           0 :       if(!mh.fromRecord(error, rec))
    1683           0 :         return false;
    1684           0 :       mLocation_p=mh.asMPosition();
    1685           0 :     }
    1686           0 :      SpectralCoordinate *tmpSpec=SpectralCoordinate::restore(inRecord, "spectralcoord");
    1687           0 :     if(tmpSpec){
    1688           0 :       spectralCoord_p=*tmpSpec;
    1689           0 :       delete tmpSpec;
    1690             :     }
    1691           0 :     visPolMap_p.resize();
    1692           0 :     if(inRecord.isDefined("ephemeristable")){
    1693           0 :       String ephemtab;
    1694           0 :       inRecord.get("ephemeristable", ephemtab);
    1695           0 :       MeasComet laComet;
    1696           0 :       if(Table::isReadable(ephemtab, False)){
    1697           0 :         Table laTable(ephemtab);
    1698           0 :         Path leSentier(ephemtab);
    1699           0 :         laComet=MeasComet(laTable, leSentier.absoluteName());
    1700           0 :       }
    1701             :       else{
    1702           0 :         laComet= MeasComet(ephemtab);
    1703             :       }
    1704           0 :       if(!mFrame_p.comet())
    1705           0 :         mFrame_p.set(laComet);
    1706             :       else
    1707           0 :         mFrame_p.resetComet(laComet);
    1708           0 :     }
    1709             : 
    1710           0 :     return retval;
    1711             :   }
    1712             : 
    1713             : 
    1714         600 :   void FTMachine::getImagingWeight(Matrix<Float>& imwgt, const vi::VisBuffer2& vb){
    1715             :     //cerr << "BRIGGSweightor " << briggsWeightor_p.null()  << " or " << !briggsWeoght_p << endl;
    1716         600 :     if(briggsWeightor_p.null()){
    1717         600 :       imwgt=vb.imagingWeight();
    1718             :     }
    1719             :     else{
    1720           0 :       briggsWeightor_p->weightUniform(imwgt, vb);
    1721             :     }
    1722             : 
    1723         600 :   }
    1724             :   // Make a plain straightforward honest-to-FSM image. This returns
    1725             :   // a complex image, without conversion to Stokes. The representation
    1726             :   // is that required for the visibilities.
    1727             :   //----------------------------------------------------------------------
    1728           0 :   void FTMachine::makeImage(FTMachine::Type type,
    1729             :                             vi::VisibilityIterator2& vi,
    1730             :                             ImageInterface<Complex>& theImage,
    1731             :                             Matrix<Float>& weight) {
    1732             : 
    1733             : 
    1734           0 :     logIO() << LogOrigin("FTMachine", "makeImage0") << LogIO::NORMAL;
    1735             : 
    1736             :     // Loop over all visibilities and pixels
    1737           0 :     vi::VisBuffer2* vb=vi.getVisBuffer();
    1738             : 
    1739             :     // Initialize put (i.e. transform to Sky) for this model
    1740           0 :     vi.origin();
    1741             : 
    1742           0 :     if(vb->polarizationFrame()==MSIter::Linear) {
    1743           0 :       StokesImageUtil::changeCStokesRep(theImage, StokesImageUtil::LINEAR);
    1744             :     }
    1745             :     else {
    1746           0 :       StokesImageUtil::changeCStokesRep(theImage, StokesImageUtil::CIRCULAR);
    1747             :     }
    1748             : 
    1749           0 :     initializeToSky(theImage,weight,*vb);
    1750             :     //This call is a NOP for all weighting schemes except for cube-briggs-perchanweightdensity
    1751           0 :     initBriggsWeightor(vi);
    1752           0 :     Bool useCorrected= !(MSColumns(vi.ms()).correctedData().isNull());
    1753           0 :     if((type==FTMachine::CORRECTED) && (!useCorrected))
    1754           0 :       type=FTMachine::OBSERVED;
    1755           0 :     Bool normalize=true;
    1756           0 :     if(type==FTMachine::COVERAGE)
    1757           0 :       normalize=false;
    1758             : 
    1759             :     // Loop over the visibilities, putting VisBuffers
    1760           0 :     for (vi.originChunks();vi.moreChunks();vi.nextChunk()) {
    1761           0 :       for (vi.origin(); vi.more(); vi.next()) {
    1762             : 
    1763           0 :         switch(type) {
    1764           0 :         case FTMachine::RESIDUAL:
    1765           0 :           vb->setVisCube(vb->visCubeCorrected());
    1766           0 :           vb->setVisCube(vb->visCube()-vb->visCubeModel());
    1767           0 :           put(*vb, -1, false);
    1768           0 :           break;
    1769           0 :         case FTMachine::MODEL:
    1770           0 :           put(*vb, -1, false, FTMachine::MODEL);
    1771           0 :           break;
    1772           0 :         case FTMachine::CORRECTED:
    1773           0 :           put(*vb, -1, false, FTMachine::CORRECTED);
    1774           0 :           break;
    1775           0 :         case FTMachine::PSF:
    1776           0 :           vb->setVisCube(Complex(1.0,0.0));
    1777           0 :           put(*vb, -1, true, FTMachine::PSF);
    1778           0 :           break;
    1779           0 :         case FTMachine::COVERAGE:
    1780           0 :           vb->setVisCube(Complex(1.0));
    1781           0 :           put(*vb, -1, true, FTMachine::COVERAGE);
    1782           0 :           break;
    1783           0 :         case FTMachine::OBSERVED:
    1784             :         default:
    1785           0 :           put(*vb, -1, false, FTMachine::OBSERVED);
    1786           0 :           break;
    1787             :         }
    1788             :       }
    1789             :     }
    1790           0 :     finalizeToSky();
    1791             :     // Normalize by dividing out weights, etc.
    1792           0 :     getImage(weight, normalize);
    1793           0 :   }
    1794             : 
    1795             : 
    1796             : 
    1797             : 
    1798           0 :   Bool FTMachine::setFrameValidity(Bool validFrame){
    1799             : 
    1800           0 :     freqFrameValid_p=validFrame;
    1801           0 :     return true;
    1802             :   }
    1803             : 
    1804             : 
    1805           0 :   Vector<Int> FTMachine::channelMap(const vi::VisBuffer2& vb){
    1806           0 :     matchChannel(vb);
    1807           0 :     return chanMap;
    1808             :   }
    1809        1206 :   Bool FTMachine::matchChannel(const vi::VisBuffer2& vb){
    1810             :     //Int spw=vb.spectralWindows()[0];
    1811        1206 :     nvischan  = vb.nChannels();
    1812        1206 :     chanMap.resize(nvischan);
    1813        1206 :     chanMap.set(-1);
    1814        1206 :     Vector<Double> lsrFreq(0);
    1815             : 
    1816             :     //cerr << "doConve " << spw << "   " << doConversion_p[spw] << " freqframeval " << freqFrameValid_p << endl;
    1817             :     //cerr <<"valid frame " << freqFrameValid_p << " polmap "<< polMap << endl;
    1818             :     //cerr << "spectral coord system " << spectralCoord_p.frequencySystem(False) << endl;
    1819        1206 :     if (freqFrameValid_p &&spectralCoord_p.frequencySystem(False)!=MFrequency::REST ) {
    1820           0 :       lsrFreq=vb.getFrequencies(0,MFrequency::LSRK);
    1821             :     }
    1822             :     else {
    1823        1206 :       lsrFreq=vb.getFrequencies(0);
    1824             :     }
    1825        1206 :     if (spectralCoord_p.frequencySystem(False)==MFrequency::REST && fixMovingSource_p) {
    1826           0 :       if (lastMSId_p != vb.msId()) {
    1827           0 :         romscol_p=new MSColumns(vb.ms());
    1828             :         //if ms changed ...reset ephem table
    1829           0 :         if (upcase(movingDir_p.getRefString()).contains("APP")) {
    1830           0 :           MeasComet mcomet(Path((romscol_p->field()).ephemPath(vb.fieldId()(0))).absoluteName());
    1831           0 :           mFrame_p.resetComet(mcomet);
    1832           0 :         }
    1833             :       }
    1834           0 :       MEpoch e0 (Quantity(vb.time()(0), "s"));
    1835           0 :       mFrame_p.epoch() ? mFrame_p.resetEpoch(e0)
    1836           0 :                        : mFrame_p.set(e0);
    1837             : 
    1838           0 :       const auto ephemDirection = vbutil_p->getEphemDir(vb, phaseCenterTime_p);
    1839           0 :       mFrame_p.direction() ? mFrame_p.resetDirection(ephemDirection)
    1840           0 :                            : mFrame_p.set(ephemDirection);
    1841             : 
    1842           0 :       shiftFreqToSource(lsrFreq);
    1843           0 :     }
    1844             :      //cerr << "lsrFreq " << lsrFreq.shape() << " nvischan " << nvischan << endl;
    1845             :      //     if(doConversion_p.nelements() < uInt(spw+1))
    1846             :      //  doConversion_p.resize(spw+1, true);
    1847             :      // doConversion_p[spw]=freqFrameValid_p;
    1848             : 
    1849        1206 :       if(lsrFreq.nelements() ==0){
    1850           0 :         matchPol(vb);
    1851           0 :         return false;
    1852             :       }
    1853        1206 :       lsrFreq_p.resize(lsrFreq.nelements());
    1854        1206 :       lsrFreq_p=lsrFreq;
    1855        1206 :       Vector<Double> c(1);
    1856        1206 :       c=0.0;
    1857        1206 :       Vector<Double> f(1);
    1858        1206 :       Int nFound=0;
    1859             : 
    1860             :       Double minFreq;
    1861             :       Double maxFreq;
    1862        1206 :       spectralCoord_p.toWorld(minFreq, Double(0));
    1863        1206 :       spectralCoord_p.toWorld(maxFreq, Double(nchan));
    1864        1206 :       if(maxFreq < minFreq){
    1865           0 :         f(0)=minFreq;
    1866           0 :         minFreq=maxFreq;
    1867           0 :         maxFreq=f(0);
    1868             :       }
    1869             : 
    1870             : 
    1871             :       //cout.precision(10);
    1872      121806 :       for (Int chan=0;chan<nvischan;chan++) {
    1873      120600 :         f(0)=lsrFreq[chan];
    1874      120600 :         if(spectralCoord_p.toPixel(c, f)) {
    1875      120600 :         Int pixel=Int(floor(c(0)+0.5));  // round to chan freq at chan center
    1876             :         //cerr << " chan " << chan << " f " << f(0) << " pixel "<< c(0) << "  " << pixel << endl;
    1877             :         /////////////
    1878             :         //c(0)=pixel;
    1879             :         //spectralCoord_p.toWorld(f, c);
    1880             :         //cerr << "f1 " << f(0) << " pixel "<< c(0) << "  " << pixel << endl;
    1881             :         ////////////////
    1882      120600 :         if(pixel>-1&&pixel<nchan) {
    1883        1206 :           chanMap(chan)=pixel;
    1884        1206 :           nFound++;
    1885        1206 :           if(nvischan>1&&(chan==0||chan==nvischan-1)) {
    1886             :             /*logIO() << LogIO::DEBUGGING
    1887             :                     << "Selected visibility channel : " << chan+1
    1888             :                     << " has frequency "
    1889             :                     <<  MFrequency(Quantity(f(0), "Hz")).get("GHz").getValue()
    1890             :                     << " GHz and maps to image pixel " << pixel+1 << LogIO::POST;
    1891             :             */
    1892             :           }
    1893             :         }
    1894             :         else{
    1895             : 
    1896      119394 :           if(nvischan > 1){
    1897      119394 :             Double fwidth=lsrFreq[1]-lsrFreq[0];
    1898      119394 :             Double limit=0;
    1899             :             //Double where=c(0)*fabs(spectralCoord_p.increment()(0));
    1900      119394 :             if( freqInterpMethod_p==InterpolateArray1D<Double,Complex>::linear)
    1901           0 :               limit=2;
    1902      119394 :             else if( freqInterpMethod_p==InterpolateArray1D<Double,Complex>::cubic ||  freqInterpMethod_p==InterpolateArray1D<Double,Complex>::spline)
    1903           0 :               limit=4;
    1904             :             //cerr<< "where " << where << " pixel " << pixel << " fwidth " << fwidth << endl;
    1905             :             /*
    1906             :             if(((pixel<0) && (where >= (0-limit*fabs(fwidth)))) )
    1907             :               chanMap(chan)=-2;
    1908             :             if((pixel>=nchan) ) {
    1909             :               where=f(0);
    1910             :               Double fend;
    1911             :               spectralCoord_p.toWorld(fend, Double(nchan));
    1912             :               if( ( (fwidth >0) &&where < (fend+limit*fwidth))  || ( (fwidth <0) &&where > (fend+limit*fwidth)) )
    1913             :                 chanMap(chan)=-2;
    1914             :             }
    1915             :             */
    1916             : 
    1917      119394 :             if((f(0) <  (maxFreq + limit*fabs(fwidth))) && (f(0) >(maxFreq-0.5*fabs(fwidth)))){
    1918           0 :               chanMap(chan)=-2;
    1919             :             }
    1920      119394 :             if((f(0) < minFreq+0.5*fabs(fwidth)) &&  (f(0) > (minFreq-limit*fabs(fwidth)))){
    1921           0 :               chanMap(chan)=-2;
    1922             :             }
    1923             :           }
    1924             : 
    1925             : 
    1926             :         }
    1927             :         }
    1928             :       }
    1929             :       //cerr << "chanmap " << chanMap << endl;
    1930             :       /* if(multiChanMap_p.nelements() < uInt(spw+1))
    1931             :           multiChanMap_p.resize(spw+1);
    1932             :       multiChanMap_p[spw].resize();
    1933             :       multiChanMap_p[spw]=chanMap;
    1934             :       */
    1935             : 
    1936        1206 :       if(nFound==0) {
    1937             :         /*
    1938             :         logIO()  << "Visibility channels in spw " << spw+1
    1939             :         <<      " of ms " << vb.msId() << " is not being used "
    1940             :         << LogIO::WARN << LogIO::POST;
    1941             :         */
    1942           0 :         matchPol(vb); ///sometimes the polmap is needed even if chanmap failed
    1943           0 :         return false;
    1944             :       }
    1945             : 
    1946        1206 :       return matchPol(vb);
    1947             : 
    1948             : 
    1949             : 
    1950        1206 :     }
    1951             : 
    1952        1206 :   Bool FTMachine::matchPol(const vi::VisBuffer2& vb){
    1953        1206 :     Vector<Stokes::StokesTypes> visPolMap(vb.getCorrelationTypesSelected());
    1954        1206 :     if((polMap.nelements() > 0) &&(visPolMap.nelements() == visPolMap_p.nelements()) &&allEQ(visPolMap, visPolMap_p))
    1955        1200 :       return True;
    1956           6 :     Int stokesIndex=image->coordinates().findCoordinate(Coordinate::STOKES);
    1957           6 :     AlwaysAssert(stokesIndex>-1, AipsError);
    1958           6 :     StokesCoordinate stokesCoord=image->coordinates().stokesCoordinate(stokesIndex);
    1959             : 
    1960             : 
    1961           6 :     visPolMap_p.resize();
    1962           6 :     visPolMap_p=visPolMap;
    1963           6 :     nvispol=visPolMap.nelements();
    1964           6 :     AlwaysAssert(nvispol>0, AipsError);
    1965           6 :     polMap.resize(nvispol);
    1966           6 :     polMap=-1;
    1967           6 :     Int pol=0;
    1968           6 :     Bool found=false;
    1969             :     // First we try matching Stokes in the visibilities to
    1970             :     // Stokes in the image that we are gridding into.
    1971          30 :     for (pol=0;pol<nvispol;pol++) {
    1972          24 :       Int p=0;
    1973          24 :       if(stokesCoord.toPixel(p, Stokes::type(visPolMap(pol)))) {
    1974           0 :         AlwaysAssert(p<npol, AipsError);
    1975           0 :         polMap(pol)=p;
    1976           0 :         found=true;
    1977             :       }
    1978             :     }
    1979             :       // If this fails then perhaps we were looking to grid I
    1980             :       // directly. If so then we need to check that the parallel
    1981             :       // hands are present in the visibilities.
    1982           6 :     if(!found) {
    1983           6 :       Int p=0;
    1984           6 :       if(stokesCoord.toPixel(p, Stokes::I)) {
    1985           6 :         polMap=-1;
    1986           6 :         if(vb.polarizationFrame()==MSIter::Linear) {
    1987           0 :           p=0;
    1988           0 :           for (pol=0;pol<nvispol;pol++) {
    1989           0 :             if(Stokes::type(visPolMap(pol))==Stokes::XX)
    1990           0 :               {polMap(pol)=0;p++;found=true;};
    1991           0 :             if(Stokes::type(visPolMap(pol))==Stokes::YY)
    1992           0 :               {polMap(pol)=0;p++;found=true;};
    1993             :           }
    1994             :         }
    1995             :         else {
    1996           6 :           p=0;
    1997          30 :           for (pol=0;pol<nvispol;pol++) {
    1998          24 :             if(Stokes::type(visPolMap(pol))==Stokes::LL)
    1999           6 :               {polMap(pol)=0;p++;found=true;};
    2000          24 :             if(Stokes::type(visPolMap(pol))==Stokes::RR)
    2001           6 :               {polMap(pol)=0;p++;found=true;};
    2002             :           }
    2003             :         }
    2004           6 :         if(!found) {
    2005             :           logIO() <<  "Cannot find polarization map: visibility polarizations = "
    2006           0 :                                         << visPolMap << LogIO::EXCEPTION;
    2007             :         }
    2008             :         else {
    2009             : 
    2010             :                 //logIO() << LogIO::DEBUGGING << "Transforming I only" << LogIO::POST;
    2011             :         }
    2012             :       };
    2013             :     }
    2014           6 :     return True;
    2015        1206 :   }
    2016             : 
    2017           0 :   Vector<String> FTMachine::cleanupTempFiles(const String& mess){
    2018           0 :     briggsWeightor_p=nullptr;
    2019           0 :     for(uInt k=0; k < tempFileNames_p.nelements(); ++k){
    2020           0 :       if(Table::isReadable(tempFileNames_p[k])){
    2021           0 :         if(mess.size()==0){
    2022             :           try{
    2023           0 :             Table::deleteTable(tempFileNames_p[k]);
    2024             :           }
    2025           0 :           catch(AipsError &x){
    2026           0 :             logIO() << LogOrigin("FTMachine", "cleanupTempFiles") << LogIO::NORMAL;
    2027           0 :             logIO() <<  LogIO::WARN<< "YOU may have to delete the temporary file " << tempFileNames_p[k] << " because " << x.getMesg()  << LogIO::POST;
    2028             : 
    2029           0 :           }
    2030             :         }
    2031             :         else{
    2032           0 :           logIO() << LogOrigin("FTMachine", "cleanupTempFiles") << LogIO::NORMAL;
    2033           0 :           logIO() << "YOU have to delete the temporary file " << tempFileNames_p[k] << " because " << mess << LogIO::DEBUG1 << LogIO::POST;
    2034             :         }
    2035             :       }
    2036             :     }
    2037           0 :     return tempFileNames_p;
    2038             :   }
    2039         800 :   void FTMachine::gridOk(Int convSupport){
    2040             : 
    2041         800 :     if (nx <= 2*convSupport) {
    2042           0 :       logIO_p
    2043             :         << "number of pixels "
    2044             :         << nx << " on x axis is smaller that the gridding support "
    2045             :         << 2*convSupport   << " Please use a larger value "
    2046           0 :         << LogIO::EXCEPTION;
    2047             :     }
    2048             : 
    2049         800 :     if (ny <= 2*convSupport) {
    2050           0 :       logIO_p
    2051             :         << "number of pixels "
    2052             :         << ny << " on y axis is smaller that the gridding support "
    2053             :         << 2*convSupport   << " Please use a larger value "
    2054           0 :         << LogIO::EXCEPTION;
    2055             :     }
    2056             : 
    2057         800 :   }
    2058             : 
    2059           0 :   void FTMachine::setLocation(const MPosition& loc){
    2060             : 
    2061           0 :     mLocation_p=loc;
    2062             : 
    2063           0 :   }
    2064             : 
    2065           0 :   MPosition& FTMachine::getLocation(){
    2066             : 
    2067           0 :     return mLocation_p;
    2068             :   }
    2069             : 
    2070             : 
    2071           0 :   void FTMachine::setMovingSource(const String& sname, const String& ephtab){
    2072           0 :     String sourcename=sname;
    2073           0 :     String ephemtab=ephtab;
    2074             :     //if a table is given as sourcename...assume ephemerides
    2075           0 :     if(Table::isReadable(sourcename, False)){
    2076           0 :       sourcename="COMET";
    2077           0 :       ephemtab=sname;
    2078           0 :       ephemTableName_p = sname;
    2079             :     }
    2080             :     ///Special case
    2081           0 :     if(upcase(sourcename)=="TRACKFIELD"){
    2082             :       //if(name().contains("MosaicFT"))
    2083             :       //        throw(AipsError("Cannot use field phasecenter to track moving source in a Mosaic"));
    2084           0 :       fixMovingSource_p=True;
    2085           0 :       movingDir_p=MDirection(Quantity(0.0,"deg"), Quantity(90.0, "deg"));
    2086           0 :       movingDir_p.setRefString("APP");
    2087             :       ///Setting it to APP with movingDir_p==True  => should use the phasecenter to track
    2088             :       ///Discussion in CAS-9004 where users are too lazy to give an ephemtable.
    2089           0 :       return;
    2090             :     }
    2091             : 
    2092             :     MDirection::Types refType;
    2093           0 :     Bool  isValid = MDirection::getType(refType, sourcename);
    2094           0 :     if(!isValid)
    2095           0 :       throw(AipsError("Cannot recognize moving source "+sourcename));
    2096           0 :     if(refType < MDirection::N_Types || refType > MDirection:: N_Planets )
    2097           0 :       throw(AipsError(sourcename+" is not type of source we can track"));
    2098           0 :     if(refType==MDirection::COMET){
    2099           0 :       MeasComet laComet;
    2100           0 :       if(Table::isReadable(ephemtab, False)){
    2101           0 :         Table laTable(ephemtab);
    2102           0 :         Path leSentier(ephemtab);
    2103           0 :         laComet=MeasComet(laTable, leSentier.absoluteName());
    2104           0 :       }
    2105             :       else{
    2106           0 :         laComet= MeasComet(ephemtab);
    2107             :       }
    2108           0 :       if(!mFrame_p.comet())
    2109           0 :         mFrame_p.set(laComet);
    2110             :       else
    2111           0 :         mFrame_p.resetComet(laComet);
    2112           0 :     }
    2113           0 :     fixMovingSource_p=true;
    2114           0 :     movingDir_p=MDirection(Quantity(0.0,"deg"), Quantity(90.0, "deg"));
    2115           0 :     movingDir_p.setRefString(sourcename);
    2116             :     // cerr << "movingdir " << movingDir_p.toString() << endl;
    2117           0 :   }
    2118             : 
    2119             : 
    2120           0 :   void FTMachine::setMovingSource(const MDirection& mdir){
    2121             : 
    2122           0 :     fixMovingSource_p=true;
    2123           0 :     movingDir_p=mdir;
    2124             : 
    2125           0 :   }
    2126             : 
    2127           1 :   void FTMachine::setFreqInterpolation(const String& method){
    2128             : 
    2129           1 :     String meth=method;
    2130           1 :     meth.downcase();
    2131           1 :     if(meth.contains("linear")){
    2132           0 :       freqInterpMethod_p=InterpolateArray1D<Double,Complex>::linear;
    2133             :     }
    2134           1 :     else if(meth.contains("splin")){
    2135           0 :       freqInterpMethod_p=InterpolateArray1D<Double,Complex>::spline;
    2136             :     }
    2137           1 :     else if(meth.contains("cub")){
    2138           0 :       freqInterpMethod_p=InterpolateArray1D<Double,Complex>::cubic;
    2139             :     }
    2140             :     else{
    2141           1 :       freqInterpMethod_p=InterpolateArray1D<Double,Complex>::nearestNeighbour;
    2142             :     }
    2143             : 
    2144           1 :   }
    2145           0 :   void FTMachine::setFreqInterpolation(const InterpolateArray1D<Double,Complex>::InterpolationMethod type){
    2146           0 :     freqInterpMethod_p=type;
    2147           0 :   }
    2148             : 
    2149             :   // helper function to swap the y and z axes of a Cube
    2150           0 :   void FTMachine::swapyz(Cube<Complex>& out, const Cube<Complex>& in)
    2151             :   {
    2152           0 :     IPosition inShape=in.shape();
    2153           0 :     uInt nxx=inShape(0),nyy=inShape(2),nzz=inShape(1);
    2154             :     //resize breaks  references...so out better have the right shape
    2155             :     //if references is not to be broken
    2156           0 :     if(out.nelements()==0)
    2157           0 :       out.resize(nxx,nyy,nzz);
    2158             :     Bool deleteIn,deleteOut;
    2159           0 :     const Complex* pin = in.getStorage(deleteIn);
    2160           0 :     Complex* pout = out.getStorage(deleteOut);
    2161           0 :     uInt i=0, zOffset=0;
    2162           0 :     for (uInt iz=0; iz<nzz; ++iz, zOffset+=nxx) {
    2163           0 :       Int yOffset=zOffset;
    2164           0 :       for (uInt iy=0; iy<nyy; ++iy, yOffset+=nxx*nzz) {
    2165           0 :         for (uInt ix=0; ix<nxx; ++ix){
    2166           0 :           pout[i++] = pin[ix+yOffset];
    2167             :         }
    2168             :       }
    2169             :     }
    2170           0 :     out.putStorage(pout,deleteOut);
    2171           0 :     in.freeStorage(pin,deleteIn);
    2172           0 :   }
    2173             : 
    2174           0 :   void FTMachine::swapyz(Cube<Complex>& out, const Cube<Bool>& outFlag, const Cube<Complex>& in)
    2175             :   {
    2176           0 :     IPosition inShape=in.shape();
    2177           0 :     uInt nxx=inShape(0),nyy=inShape(2),nzz=inShape(1);
    2178             :     //resize breaks  references...so out better have the right shape
    2179             :     //if references is not to be broken
    2180           0 :     if(out.nelements()==0)
    2181           0 :       out.resize(nxx,nyy,nzz);
    2182             :     Bool deleteIn,deleteOut, delFlag;
    2183           0 :     const Complex* pin = in.getStorage(deleteIn);
    2184           0 :     const Bool* poutflag= outFlag.getStorage(delFlag);
    2185           0 :     Complex* pout = out.getStorage(deleteOut);
    2186           0 :     uInt i=0, zOffset=0;
    2187           0 :     for (uInt iz=0; iz<nzz; ++iz, zOffset+=nxx) {
    2188           0 :       Int yOffset=zOffset;
    2189           0 :       for (uInt iy=0; iy<nyy; ++iy, yOffset+=nxx*nzz) {
    2190           0 :         for (uInt ix=0; ix<nxx; ++ix){
    2191           0 :           if(!poutflag[i])
    2192           0 :             pout[i] = pin[ix+yOffset];
    2193           0 :           ++i;
    2194             :         }
    2195             :       }
    2196             :     }
    2197           0 :     out.putStorage(pout,deleteOut);
    2198           0 :     in.freeStorage(pin,deleteIn);
    2199           0 :     outFlag.freeStorage(poutflag, delFlag);
    2200           0 :   }
    2201             : 
    2202             :   // helper function to swap the y and z axes of a Cube
    2203           0 :   void FTMachine::swapyz(Cube<Bool>& out, const Cube<Bool>& in)
    2204             :   {
    2205           0 :     IPosition inShape=in.shape();
    2206           0 :     uInt nxx=inShape(0),nyy=inShape(2),nzz=inShape(1);
    2207           0 :     if(out.nelements()==0)
    2208           0 :       out.resize(nxx,nyy,nzz);
    2209             :     Bool deleteIn,deleteOut;
    2210           0 :     const Bool* pin = in.getStorage(deleteIn);
    2211           0 :     Bool* pout = out.getStorage(deleteOut);
    2212           0 :     uInt i=0, zOffset=0;
    2213           0 :     for (uInt iz=0; iz<nzz; iz++, zOffset+=nxx) {
    2214           0 :       Int yOffset=zOffset;
    2215           0 :       for (uInt iy=0; iy<nyy; iy++, yOffset+=nxx*nzz) {
    2216           0 :         for (uInt ix=0; ix<nxx; ix++) pout[i++] = pin[ix+yOffset];
    2217             :       }
    2218             :     }
    2219           0 :     out.putStorage(pout,deleteOut);
    2220           0 :     in.freeStorage(pin,deleteIn);
    2221           0 :   }
    2222             : 
    2223           0 :   void FTMachine::setPointingDirColumn(const String& column){
    2224           0 :     pointingDirCol_p=column;
    2225           0 :     pointingDirCol_p.upcase();
    2226           0 :     if( (pointingDirCol_p != "DIRECTION") &&(pointingDirCol_p != "TARGET") && (pointingDirCol_p != "ENCODER") && (pointingDirCol_p != "POINTING_OFFSET") && (pointingDirCol_p != "SOURCE_OFFSET")){
    2227             : 
    2228             :       //basically at this stage you don't know what you're doing...so you get the default
    2229             : 
    2230           0 :       pointingDirCol_p="DIRECTION";
    2231             : 
    2232             :     }
    2233           0 :   }
    2234             : 
    2235           0 :   String FTMachine::getPointingDirColumnInUse(){
    2236             : 
    2237           0 :     return pointingDirCol_p;
    2238             : 
    2239             :   }
    2240             : 
    2241           0 :   void FTMachine::setSpwChanSelection(const Cube<Int>& spwchansels) {
    2242           0 :     spwChanSelFlag_p.resize();
    2243           0 :     spwChanSelFlag_p=spwchansels;
    2244           0 :   }
    2245             : 
    2246           0 :   void FTMachine::setSpwFreqSelection(const Matrix<Double>& spwFreqs)
    2247             :   {
    2248           0 :     spwFreqSel_p.assign(spwFreqs);
    2249           0 :     SynthesisUtils::expandFreqSelection(spwFreqs,expandedSpwFreqSel_p, expandedSpwConjFreqSel_p);
    2250           0 :   }
    2251             : 
    2252        1200 :   void FTMachine::setSpectralFlag(const vi::VisBuffer2& vb, Cube<Bool>& modflagcube){
    2253             : 
    2254        1200 :       modflagcube.resize(vb.flagCube().shape());
    2255        1200 :       modflagcube=vb.flagCube();
    2256        1200 :       if(!isPseudoI_p){
    2257        1200 :         ArrayIterator<Bool> from(modflagcube, IPosition(1, 0));
    2258    42121200 :         while(!from.pastEnd()){
    2259    42120000 :           if(anyTrue(from.array()))
    2260           0 :             from.array().set(True);
    2261    42120000 :           from.next();
    2262             :         }
    2263        1200 :       }
    2264        1200 :       uInt nchan = vb.nChannels();
    2265        1200 :       uInt msid = vb.msId();
    2266        1200 :       uInt selspw = vb.spectralWindows()[0];
    2267        1200 :       Bool spwFlagIsSet=( (spwChanSelFlag_p.nelements() > 0) && (spwChanSelFlag_p.shape()(1) > selspw) &&
    2268        1200 :                         (spwChanSelFlag_p.shape()(0) > msid) &&
    2269           0 :                         (spwChanSelFlag_p.shape()(2) >=nchan));
    2270             :       //cerr << "spwFlagIsSet " << spwFlagIsSet << endl;
    2271      121200 :       for (uInt i=0;i<nchan;i++) {
    2272             :         //Flag those channels that  did not get selected...
    2273             :         //respect the flags from vb  if selected  or
    2274             :         //if spwChanSelFlag is wrong shape
    2275      120000 :         if ((spwFlagIsSet) && (spwChanSelFlag_p(msid,selspw,i)!=1)) {
    2276           0 :         modflagcube.xzPlane(i).set(true);
    2277             :         }
    2278             :       }
    2279        1200 :     }
    2280             : 
    2281        1200 :   Matrix<Double> FTMachine::negateUV(const vi::VisBuffer2& vb){
    2282        1200 :     Matrix<Double> uvw(vb.uvw().shape());
    2283      422400 :     for (rownr_t i=0;i< vb.nRows() ; ++i) {
    2284     1263600 :       for (Int idim=0;idim<2; ++idim) uvw(idim,i)=-vb.uvw()(idim, i);
    2285      421200 :       uvw(2,i)=vb.uvw()(2,i);
    2286             :     }
    2287        1200 :     return uvw;
    2288           0 :   }
    2289             :   //-----------------------------------------------------------------------------------------------------------------
    2290             :   //------------  Vectorized versions of initializeToVis, initializeToSky, finalizeToSky
    2291             :   //------------  that are called from CubeSkyEquation.
    2292             :   //------------  They call getImage,getWeightImage, which are implemented in all FTMs
    2293             :   //------------  Also, Correlation / Stokes conversions and gS/ggS normalizations.
    2294             : 
    2295             : 
    2296           0 :   void FTMachine::setSkyJones(Vector<CountedPtr<casa::refim::SkyJones> >& sj){
    2297           0 :     sj_p.resize();
    2298           0 :     sj_p=sj;
    2299           0 :     cout << "FTM : Set Sky Jones of length " << sj_p.nelements() << " and types ";
    2300           0 :     for( uInt i=0;i<sj_p.nelements();i++) cout << sj_p[i]->type() << " ";
    2301           0 :     cout << endl;
    2302           0 :   }
    2303             :   // Convert complex correlation planes to float Stokes planes
    2304           0 :   void FTMachine::correlationToStokes(ImageInterface<Complex>& compImage,
    2305             :                                       ImageInterface<Float>& resImage,
    2306             :                                       const Bool dopsf)
    2307             :   {
    2308             :     // Convert correlation image to IQUV format
    2309           0 :     AlwaysAssert(compImage.shape()[0]==resImage.shape()[0], AipsError);
    2310           0 :     AlwaysAssert(compImage.shape()[1]==resImage.shape()[1], AipsError);
    2311           0 :     AlwaysAssert(compImage.shape()[3]==resImage.shape()[3], AipsError);
    2312             : 
    2313           0 :     if(dopsf)
    2314             :       {
    2315             :         // For the PSF, choose only those stokes planes that have a valid PSF
    2316           0 :         StokesImageUtil::ToStokesPSF(resImage,compImage);
    2317             :       }
    2318             :     else
    2319             :       {
    2320           0 :         StokesImageUtil::To(resImage,compImage);
    2321             :       }
    2322           0 :   };
    2323             : 
    2324             :   // Convert float Stokes planes to complex correlation planes
    2325           0 :   void FTMachine::stokesToCorrelation(ImageInterface<Float>& modelImage,
    2326             :                                       ImageInterface<Complex>& compImage)
    2327             :   {
    2328             :     /*
    2329             :     StokesCoordinate stcomp=compImage.coordinates().stokesCoordinate(compImage.coordinates().findCoordinate(Coordinate::STOKES));
    2330             :     StokesCoordinate stfloat = modelImage.coordinates().stokesCoordinate(modelImage.coordinates().findCoordinate(Coordinate::STOKES));
    2331             : 
    2332             :     cout << "Stokes types : complex : " << stcomp.stokes() << "    float : " << stfloat.stokes() << endl;
    2333             :     cout << "Shapes : complex : " << compImage.shape() << "   float : " << modelImage.shape() << endl;
    2334             :     */
    2335             : 
    2336             :     //Pol axis need not be same
    2337           0 :     AlwaysAssert(modelImage.shape()[0]==compImage.shape()[0], AipsError);
    2338           0 :     AlwaysAssert(modelImage.shape()[1]==compImage.shape()[1], AipsError);
    2339           0 :     AlwaysAssert(modelImage.shape()[3]==compImage.shape()[3], AipsError);
    2340             :     // Convert from Stokes to Complex
    2341           0 :     StokesImageUtil::From(compImage, modelImage);
    2342           0 :   };
    2343             : 
    2344             :   //------------------------------------------------------------------------------------------------------------------
    2345             : 
    2346           0 :   void FTMachine::normalizeImage(ImageInterface<Float>& skyImage,
    2347             :                                  Matrix<Float>& sumOfWts,
    2348             :                                  ImageInterface<Float>& sensitivityImage,
    2349             :                                  Bool dopsf, Float pblimit, Int normtype)
    2350             :   {
    2351             : 
    2352             :     //Normalize the sky Image
    2353           0 :     Int nXX=(skyImage).shape()(0);
    2354           0 :     Int nYY=(skyImage).shape()(1);
    2355           0 :     Int npola= (skyImage).shape()(2);
    2356           0 :     Int nchana= (skyImage).shape()(3);
    2357             : 
    2358           0 :       IPosition pcentre(4,nXX/2,nYY/2,0,0);
    2359             :     // IPosition psource(4,nXX/2+22,nYY/2,0,0);
    2360             : 
    2361             :     //    storeImg(String("norm_resimage.im") , skyImage);
    2362             :     //    storeImg(String("norm_sensitivity.im"), sensitivityImage);
    2363             : 
    2364             :       /////    cout << "FTM::norm : pblimit : " << pblimit << endl;
    2365             : 
    2366             :     // Note : This is needed because initial prediction has no info about sumwt.
    2367             :     // Not a clean solution.  // ForSB -- if you see a better way, go for it.
    2368           0 :     if(sumOfWts.shape() != IPosition(2,npola,nchana))
    2369             :       {
    2370           0 :         cout << "Empty SumWt.... resizing and filling with 1.0" << endl;
    2371           0 :         sumOfWts.resize(IPosition(2,npola,nchana));
    2372           0 :         sumOfWts=1.0;
    2373             :       }
    2374             : 
    2375             :     //    if(dopsf)  cout << "*** FTM::normalizeImage : Image Center : " << skyImage.getAt(pcentre) << "  and weightImage : " << sensitivityImage.getAt(pcentre) << "  SumWt : " << sumOfWts[0,0];
    2376             :     //    else  cout << "*** FTM::normalizeImage : Source Loc : " << skyImage.getAt(psource) << "  and weightImage : " << sensitivityImage.getAt(psource) << "  SumWt : " << sumOfWts[0,0];
    2377             : 
    2378             : 
    2379             : 
    2380           0 :     IPosition blc(4,nXX, nYY, npola, nchana);
    2381           0 :     IPosition trc(4, nXX, nYY, npola, nchana);
    2382           0 :     blc(0)=0; blc(1)=0; trc(0)=nXX-1; trc(1)=nYY-1;
    2383             :     //max weights per plane
    2384           0 :     for (Int pol=0; pol < npola; ++pol){
    2385           0 :       for (Int chan=0; chan < nchana ; ++chan){
    2386             : 
    2387           0 :         blc(2)=pol; trc(2)=pol;
    2388           0 :         blc(3)=chan; trc(3)=chan;
    2389           0 :         Slicer sl(blc, trc, Slicer::endIsLast);
    2390           0 :         SubImage<Float> subSkyImage(skyImage, sl, false);
    2391           0 :         SubImage<Float> subSensitivityImage(sensitivityImage, sl, false);
    2392           0 :         SubImage<Float> subOutput(skyImage, sl, true);
    2393           0 :         Float sumWt = sumOfWts(pol,chan);
    2394           0 :         if(sumWt > 0.0){
    2395           0 :           switch(normtype)
    2396             :             {
    2397           0 :             case 0: // only sum Of Weights - FTM only (ForSB)
    2398           0 :               subOutput.copyData( (LatticeExpr<Float>)
    2399           0 :                                   ((dopsf?1.0:-1.0)*subSkyImage/(sumWt)));
    2400           0 :               break;
    2401             : 
    2402           0 :             case 1: // only sensitivityImage   Ic/avgPB  (ForSB)
    2403           0 :               subOutput.copyData( (LatticeExpr<Float>)
    2404           0 :                                   (iif(subSensitivityImage > (pblimit),
    2405           0 :                                        (subSkyImage/(subSensitivityImage)),
    2406             :                                        (subSkyImage))));
    2407             :                                        // 0.0)));
    2408           0 :               break;
    2409             : 
    2410           0 :             case 2: // sum of Weights and sensitivityImage  IGridded/(SoW*avgPB) and PSF --> Id (ForSB)
    2411           0 :               subOutput.copyData( (LatticeExpr<Float>)
    2412           0 :                                   (iif(subSensitivityImage > (pblimit),
    2413           0 :                                        ((dopsf?1.0:-1.0)*subSkyImage/(subSensitivityImage*sumWt)),
    2414             :                                        //((dopsf?1.0:-1.0)*subSkyImage))));
    2415             :                                        0.0)));
    2416           0 :               break;
    2417             : 
    2418           0 :             case 3: // MULTIPLY by the sensitivityImage  avgPB
    2419           0 :               subOutput.copyData( (LatticeExpr<Float>) (subSkyImage * subSensitivityImage) );
    2420           0 :               break;
    2421             : 
    2422           0 :             case 4: // DIVIDE by sqrt of sensitivityImage
    2423           0 :               subOutput.copyData( (LatticeExpr<Float>)
    2424           0 :                                   (iif((subSensitivityImage) > (pblimit),
    2425           0 :                                        (subSkyImage/(sqrt(subSensitivityImage))),
    2426             :                                        (subSkyImage))));
    2427             :                                        //0.0)));
    2428           0 :               break;
    2429             : 
    2430           0 :             case 5: // MULTIPLY by sqrt of sensitivityImage
    2431           0 :               subOutput.copyData( (LatticeExpr<Float>)
    2432           0 :                                   (iif((subSensitivityImage) > (pblimit),
    2433           0 :                                        (subSkyImage * (sqrt(subSensitivityImage))),
    2434             :                                        (subSkyImage))));
    2435             : 
    2436           0 :               break;
    2437             : 
    2438           0 :             case 6: // divide by non normalized sensitivity image
    2439             :               {
    2440           0 :                 Float elpblimit=max( subSensitivityImage).getFloat() * pblimit;
    2441           0 :                 subOutput.copyData( (LatticeExpr<Float>)
    2442           0 :                                     (iif(subSensitivityImage > (elpblimit),
    2443           0 :                                          ((dopsf?1.0:-1.0)*subSkyImage/(subSensitivityImage)),
    2444             :                                          0.0)));
    2445             :               }
    2446           0 :               break;
    2447           0 :             default:
    2448           0 :               throw(AipsError("Unrecognized norm-type in FTM::normalizeImage : "+String::toString(normtype)));
    2449             :             }
    2450             :         }
    2451             :         else{
    2452           0 :           subOutput.set(0.0);
    2453             :         }
    2454           0 :       }
    2455             :     }
    2456             : 
    2457             :     //if(dopsf)  cout << " Normalized (" << normtype << ") Image Center : " << skyImage.getAt(pcentre) << endl;
    2458             :      //     else  cout << " Normalized (" << normtype << ") Source Loc : " << skyImage.getAt(psource) << endl;
    2459             : 
    2460           0 :   }
    2461             : 
    2462             :   ///////////////////////////////////////////////////////////////////////////////////////////////////////
    2463             :   ///////////////////////////////////////////////////////////////////////////////////////////////////////
    2464             :   ///////////////////////////////////////////////////////////////////////////////////////////////////////
    2465             :   /////  For use with the new framework
    2466             :   ///// (Sorry about these copies, but need to keep old system working)
    2467             :   ///////////////////////////////////////////////////////////////////////////////////////////////////////
    2468             :   ///////////////////////////////////////////////////////////////////////////////////////////////////////
    2469             :   ///////////////////////////////////////////////////////////////////////////////////////////////////////
    2470             : 
    2471             :   // Vectorized InitializeToVis
    2472           0 :   void FTMachine::initializeToVisNew(const VisBuffer2& vb,
    2473             :                                      CountedPtr<SIImageStore> imstore)
    2474             :   {
    2475           0 :     AlwaysAssert(imstore->getNTaylorTerms(false)==1, AipsError);
    2476             : 
    2477           0 :     Matrix<Float> tempWts;
    2478             : 
    2479           0 :     if(!(imstore->forwardGrid()).get())
    2480           0 :       throw(AipsError("FTMAchine::InitializeToVisNew error imagestore has no valid grid initialized"));
    2481             :     // Convert from Stokes planes to Correlation planes
    2482           0 :     LatticeLocker lock1 (*(imstore->model()), FileLocker::Read);
    2483           0 :     stokesToCorrelation(*(imstore->model()), *(imstore->forwardGrid()));
    2484             : 
    2485           0 :     if(vb.polarizationFrame()==MSIter::Linear) {
    2486           0 :       StokesImageUtil::changeCStokesRep(*(imstore->forwardGrid()),
    2487             :                                         StokesImageUtil::LINEAR);
    2488             :     }
    2489             :     else {
    2490           0 :       StokesImageUtil::changeCStokesRep(*(imstore->forwardGrid()),
    2491             :                                         StokesImageUtil::CIRCULAR);
    2492             :     }
    2493             : 
    2494             :     //------------------------------------------------------------------------------------
    2495             :     // Image Mosaic only :  Multiply the input model with the Primary Beam
    2496           0 :     if(sj_p.nelements() >0 ){
    2497           0 :       for (uInt k=0; k < sj_p.nelements(); ++k){
    2498           0 :         (sj_p(k))->apply(*(imstore->forwardGrid()), *(imstore->forwardGrid()), vb, 0, true);
    2499             :       }
    2500             :     }
    2501             :     //------------------------------------------------------------------------------------
    2502             : 
    2503             :     // Call initializeToVis
    2504           0 :     initializeToVis(*(imstore->forwardGrid()), vb); // Pure virtual
    2505             : 
    2506           0 :   };
    2507             : 
    2508             :   // Vectorized finalizeToVis is not implemented because it does nothing and is never called.
    2509             : 
    2510             :   // Vectorized InitializeToSky
    2511           0 :   void FTMachine::initializeToSkyNew(const Bool dopsf,
    2512             :                                      const VisBuffer2& vb,
    2513             :                                      CountedPtr<SIImageStore> imstore)
    2514             : 
    2515             :   {
    2516           0 :     AlwaysAssert(imstore->getNTaylorTerms(false)==1, AipsError);
    2517             : 
    2518             :     // Make the relevant float grid.
    2519             :     // This is needed mainly for facetting (to set facet shapes), but is harmless for non-facetting.
    2520           0 :     if( dopsf ) { imstore->psf(); } else { imstore->residual(); }
    2521             : 
    2522             :     // Initialize the complex grid (i.e. tell FTMachine what array to use internally)
    2523           0 :     Matrix<Float> sumWeight;
    2524           0 :     if(!(imstore->backwardGrid()).get())
    2525           0 :       throw(AipsError("FTMAchine::InitializeToSkyNew error imagestore has no valid grid initialized"));
    2526           0 :     initializeToSky(*(imstore->backwardGrid()) , sumWeight , vb);
    2527             : 
    2528           0 :   };
    2529             : 
    2530             :   // Vectorized finalizeToSky
    2531           0 :   void FTMachine::finalizeToSkyNew(Bool dopsf,
    2532             :                                    const VisBuffer2& vb,
    2533             :                                    CountedPtr<SIImageStore> imstore  )
    2534             :   {
    2535             :     // Check vector lengths.
    2536           0 :     AlwaysAssert( imstore->getNTaylorTerms(false)==1, AipsError);
    2537             : 
    2538           0 :     Matrix<Float> sumWeights;
    2539           0 :     finalizeToSky();
    2540             : 
    2541             :     //------------------------------------------------------------------------------------
    2542             :     // Straightforward case. No extra primary beams. No image mosaic
    2543           0 :     if(sj_p.nelements() == 0 )
    2544             :       {
    2545             :         // cerr << "TYPEID " << typeid( *(imstore->psf())).name() << "     " << typeid(typeid( *(imstore->psf())).name()).name() << endl;
    2546           0 :         shared_ptr<ImageInterface<Float> > theim=dopsf ? imstore->psf() : imstore->residual();
    2547             :         //static_cast<decltype(imstore->residual())>(theim)->lock();
    2548           0 :         { LatticeLocker lock1 (*theim, FileLocker::Write);
    2549           0 :           correlationToStokes( getImage(sumWeights, false) , *theim, dopsf);
    2550           0 :         }
    2551           0 :         theim->unlock();
    2552             : 
    2553           0 :         if( (useWeightImage() && dopsf) || isSD() ) {
    2554             : 
    2555           0 :           LatticeLocker lock1 (*(imstore->weight()), FileLocker::Write);
    2556           0 :           getWeightImage( *(imstore->weight())  , sumWeights);
    2557           0 :           imstore->weight()->unlock();
    2558             : 
    2559             :           // Fill weight image only once, during PSF generation. Remember.... it is normalized only once
    2560             :           // during PSF generation.
    2561           0 :         }
    2562             : 
    2563             :         // Take sumWeights from corrToStokes here....
    2564           0 :         LatticeLocker lock1 (*(imstore->sumwt()), FileLocker::Write);
    2565           0 :         Bool donesumwt=(max(imstore->sumwt()->get()) > 0.0);
    2566           0 :         if(!donesumwt){
    2567           0 :           Matrix<Float> sumWeightStokes( (imstore->sumwt())->shape()[2], (imstore->sumwt())->shape()[3]   );
    2568           0 :         CoordinateSystem incoord=image->coordinates();
    2569           0 :         CoordinateSystem outcoord=imstore->sumwt()->coordinates();
    2570           0 :         StokesImageUtil::ToStokesSumWt(sumWeightStokes, sumWeights, outcoord, incoord);
    2571             : 
    2572             : 
    2573           0 :         Array<Float> sumWtArr(IPosition(4,1,1,sumWeights.shape()[0], sumWeights.shape()[1]));
    2574             : 
    2575           0 :         IPosition blc(4, 0, 0, 0, 0);
    2576           0 :          IPosition trc(4, 0, 0, sumWeightStokes.shape()[0]-1, sumWeightStokes.shape()[1]-1);
    2577           0 :         sumWtArr(blc, trc).reform(sumWeightStokes.shape())=sumWeightStokes;
    2578             : 
    2579             :         //StokesImageUtil::ToStokesSumWt( sumWeightStokes, sumWeights );
    2580           0 :                 AlwaysAssert( ( (imstore->sumwt())->shape()[2] == sumWeightStokes.shape()[0] ) &&
    2581             :                       ((imstore->sumwt())->shape()[3] == sumWeightStokes.shape()[1] ) , AipsError );
    2582             : 
    2583           0 :                 (imstore->sumwt())->put( sumWeightStokes.reform((imstore->sumwt())->shape()) );
    2584           0 :         }
    2585           0 :         imstore->sumwt()->unlock();
    2586             : 
    2587           0 :       }
    2588             :     //------------------------------------------------------------------------------------
    2589             :     // Image Mosaic only :  Multiply the residual, and weight image by the PB.
    2590             :     else
    2591             :       {
    2592             : 
    2593             :       // Take the FT of the gridded values. Writes into backwardGrid().
    2594           0 :       getImage(sumWeights, false);
    2595             : 
    2596             :       // Multiply complex image grid by PB.
    2597           0 :       if( !dopsf )
    2598             :         {
    2599           0 :           for (uInt k=0; k < sj_p.nelements(); ++k){
    2600           0 :             (sj_p(k))->apply(*(imstore->backwardGrid()), *(imstore->backwardGrid()), vb, 0, true);
    2601             :           }
    2602             :         }
    2603             : 
    2604             :       // Convert from correlation to Stokes onto a new temporary grid.
    2605           0 :       SubImage<Float>  targetImage( ( dopsf ? *(imstore->psf()) : *(imstore->residual()) ) , true);
    2606           0 :       TempImage<Float> temp( targetImage.shape(), targetImage.coordinates() );
    2607           0 :       correlationToStokes( *(imstore->backwardGrid()), temp, false);
    2608             : 
    2609             :       // Add the temporary Stokes image to the residual or PSF, whichever is being made.
    2610           0 :       LatticeExpr<Float> addToRes( targetImage + temp );
    2611           0 :       targetImage.copyData(addToRes);
    2612             : 
    2613             :       // Now, do the same with the weight image and sumwt ( only on the first pass )
    2614           0 :       if( dopsf )
    2615             :         {
    2616           0 :           SubImage<Float>  weightImage(  *(imstore->weight()) , true);
    2617           0 :           TempImage<Float> temp(weightImage.shape(), weightImage.coordinates());
    2618           0 :           getWeightImage(temp, sumWeights);
    2619             : 
    2620           0 :           for (uInt k=0; k < sj_p.nelements(); ++k){
    2621           0 :             (sj_p(k))->applySquare(temp,temp, vb, -1);
    2622             :           }
    2623             : 
    2624           0 :           LatticeExpr<Float> addToWgt( weightImage + temp );
    2625           0 :           weightImage.copyData(addToWgt);
    2626             : 
    2627           0 :           AlwaysAssert( ( (imstore->sumwt())->shape()[2] == sumWeights.shape()[0] ) &&
    2628             :                         ((imstore->sumwt())->shape()[3] == sumWeights.shape()[1] ) , AipsError );
    2629             : 
    2630           0 :           SubImage<Float>  sumwtImage(  *(imstore->sumwt()) , true);
    2631           0 :           TempImage<Float> temp2(sumwtImage.shape(), sumwtImage.coordinates());
    2632           0 :           temp2.put( sumWeights.reform(sumwtImage.shape()) );
    2633           0 :           LatticeExpr<Float> addToWgt2( sumwtImage + temp2 );
    2634           0 :           sumwtImage.copyData(addToWgt2);
    2635             : 
    2636             :           //cout << "In finalizeGridCoreMos : sumwt : " << sumwtImage.get() << endl;
    2637             : 
    2638           0 :         }
    2639             : 
    2640           0 :     }
    2641             :     //------------------------------------------------------------------------------------
    2642             : 
    2643             : 
    2644             : 
    2645           0 :     return;
    2646           0 :   };
    2647             : 
    2648             : 
    2649             : /////------------------------------------------------
    2650           0 : void FTMachine::finalizeToWeightImage(const VisBuffer2& vb,
    2651             :                                    CountedPtr<SIImageStore> imstore  )
    2652             :   {
    2653             :     // Check vector lengths.
    2654           0 :     AlwaysAssert( imstore->getNTaylorTerms(false)==1, AipsError);
    2655             : 
    2656           0 :     Matrix<Float> sumWeights;
    2657             : 
    2658             :     //------------------------------------------------------------------------------------
    2659             :     // Straightforward case. No extra primary beams. No image mosaic
    2660           0 :     if(sj_p.nelements() == 0 )
    2661             :       {
    2662             : 
    2663             : 
    2664           0 :         if( useWeightImage()  ) {
    2665             :           //if( name().contains("Mosaic") ){
    2666             :           {
    2667           0 :               finalizeToSky();
    2668             :             }
    2669           0 :           LatticeLocker lock1 (*(imstore->weight()), FileLocker::Write);
    2670           0 :           getWeightImage( *(imstore->weight())  , sumWeights);
    2671           0 :           imstore->weight()->unlock();
    2672             : 
    2673             :           // Fill weight image only once, during PSF generation. Remember.... it is normalized only once
    2674             :           // during PSF generation.
    2675           0 :         }
    2676           0 :         if(sumWeights.nelements() >0){
    2677             :           // Take sumWeights from corrToStokes here....
    2678           0 :           LatticeLocker lock1 (*(imstore->sumwt()), FileLocker::Write);
    2679           0 :           Matrix<Float> sumWeightStokes( (imstore->sumwt())->shape()[2], (imstore->sumwt())->shape()[3]   );
    2680           0 :           StokesImageUtil::ToStokesSumWt( sumWeightStokes, sumWeights );
    2681             : 
    2682           0 :           AlwaysAssert( ( (imstore->sumwt())->shape()[2] == sumWeightStokes.shape()[0] ) &&
    2683             :                         ((imstore->sumwt())->shape()[3] == sumWeightStokes.shape()[1] ) , AipsError );
    2684             : 
    2685           0 :           (imstore->sumwt())->put( sumWeightStokes.reform((imstore->sumwt())->shape()) );
    2686           0 :           imstore->sumwt()->unlock();
    2687           0 :         }
    2688             : 
    2689             :       }
    2690             :     //------------------------------------------------------------------------------------
    2691             :     // Image Mosaic only :  Multiply the residual, and weight image by the PB.
    2692             :     else
    2693             :       {
    2694             : 
    2695             :       // Now, do the same with the weight image and sumwt ( only on the first pass )
    2696             :         {
    2697           0 :           SubImage<Float>  weightImage(  *(imstore->weight()) , true);
    2698           0 :           TempImage<Float> temp(weightImage.shape(), weightImage.coordinates());
    2699           0 :           getWeightImage(temp, sumWeights);
    2700             : 
    2701           0 :           for (uInt k=0; k < sj_p.nelements(); ++k){
    2702           0 :             (sj_p(k))->applySquare(temp,temp, vb, -1);
    2703             :           }
    2704             : 
    2705           0 :           LatticeExpr<Float> addToWgt( weightImage + temp );
    2706           0 :           weightImage.copyData(addToWgt);
    2707             : 
    2708           0 :           AlwaysAssert( ( (imstore->sumwt())->shape()[2] == sumWeights.shape()[0] ) &&
    2709             :                         ((imstore->sumwt())->shape()[3] == sumWeights.shape()[1] ) , AipsError );
    2710             : 
    2711           0 :           SubImage<Float>  sumwtImage(  *(imstore->sumwt()) , true);
    2712           0 :           TempImage<Float> temp2(sumwtImage.shape(), sumwtImage.coordinates());
    2713           0 :           temp2.put( sumWeights.reform(sumwtImage.shape()) );
    2714           0 :           LatticeExpr<Float> addToWgt2( sumwtImage + temp2 );
    2715           0 :           sumwtImage.copyData(addToWgt2);
    2716             : 
    2717             :           //cout << "In finalizeGridCoreMos : sumwt : " << sumwtImage.get() << endl;
    2718             : 
    2719           0 :         }
    2720             : 
    2721             :       }
    2722             :     //------------------------------------------------------------------------------------
    2723             : 
    2724             : 
    2725             : 
    2726           0 :     return;
    2727           0 :   };
    2728             : 
    2729             : 
    2730             : 
    2731             : 
    2732             : /////-----------------------------------------------
    2733           0 :   Bool FTMachine::changedSkyJonesLogic(const vi::VisBuffer2& vb, Bool& firstRow, Bool& internalRow)
    2734             :   {
    2735           0 :     firstRow=false;
    2736           0 :     internalRow=false;
    2737             : 
    2738           0 :     if( sj_p.nelements()==0 )
    2739           0 :       {throw(AipsError("Internal Error : Checking changedSkyJones, but it is not yet set."));}
    2740             : 
    2741           0 :     CountedPtr<SkyJones> ej = sj_p[0];
    2742           0 :     if(ej.null())
    2743           0 :       return false;
    2744           0 :     if(ej->changed(vb,0))
    2745           0 :       firstRow=true;
    2746           0 :     Int row2temp=0;
    2747           0 :     if(ej->changedBuffer(vb,0,row2temp)) {
    2748           0 :       internalRow=true;
    2749             :     }
    2750           0 :     return (firstRow || internalRow) ;
    2751           0 :   }
    2752             : 
    2753           0 :   std::shared_ptr<std::complex<double>> FTMachine::getGridPtr(size_t& size) const
    2754             :   {
    2755           0 :     size = 0;
    2756           0 :     return std::shared_ptr<std::complex<double>>();
    2757             :   }
    2758             : 
    2759           0 :   std::shared_ptr<double> FTMachine::getSumWeightsPtr(size_t& size) const
    2760             :   {
    2761           0 :     size = 0;
    2762           0 :     return std::shared_ptr<double>();
    2763             :   }
    2764             : 
    2765           0 :   void FTMachine::setCFCache(CountedPtr<CFCache>& /*cfc*/, const Bool /*loadCFC*/)
    2766             :   {
    2767           0 :     throw(AipsError("FTMachine::setCFCache() directly called!"));
    2768             :   }
    2769             : 
    2770             : 
    2771             : 
    2772         192 : void FTMachine::findGridSector(const Int& nxp, const Int& nyp, const Int& ixsub, const Int& iysub, const Int& minx, const Int& miny, const Int& icounter, Int& x0, Int& y0, Int&  nxsub, Int& nysub, const Bool linear){
    2773             :   /* Vector<Int> ord(36);
    2774             :        ord(0)=14;
    2775             :       ord(1)=15;
    2776             :       ord(2)=20;
    2777             :       ord(3)=21;ord(4)=13;
    2778             :       ord(5)=16;ord(6)=19;ord(7)=22;ord(8)=8;ord(9)=9;
    2779             :       ord(10)=26;ord(11)=27;ord(12)=25;ord(13)=28;ord(14)=7;
    2780             :       ord(15)=10;ord(16)=32;ord(17)=33;ord(18)=2;ord(19)=3;
    2781             :       ord(20)=18;ord(21)=23;ord(22)=12;ord(23)=17;ord(24)=1;
    2782             :       ord(25)=4;ord(26)=6;ord(27)=11;ord(28)=24;ord(29)=29;
    2783             :       ord(30)=31;ord(31)=34;ord(32)=0;ord(33)=5;ord(34)=30;
    2784             :       ord(35)=35;
    2785             :       */
    2786             :   /*
    2787             :       Int ix= (icounter+1)-((icounter)/ixsub)*ixsub;
    2788             :       Int iy=(icounter)/ixsub+1;
    2789             :       y0=(nyp/iysub)*(iy-1)+1+miny;
    2790             :       nysub=nyp/iysub;
    2791             :       if( iy == iysub) {
    2792             :         nysub=nyp-(nyp/iysub)*(iy-1);
    2793             :       }
    2794             :       x0=(nxp/ixsub)*(ix-1)+1+minx;
    2795             :       nxsub=nxp/ixsub;
    2796             :       if( ix == ixsub){
    2797             :         nxsub=nxp-(nxp/ixsub)*(ix-1);
    2798             :       }
    2799             :   */
    2800             : 
    2801             : 
    2802             :       {
    2803         192 :         Int elrow=icounter/ixsub;
    2804         192 :         Int elcol=(icounter-elrow*ixsub);
    2805             :         //cerr << "row "<< elrow << " col " << elcol << endl;
    2806             :         //nxsub=Int(floor(((ceil(fabs(float(2*elcol+1-ixsub)/2.0))-1.0)*5 +1)*nxp/36.0 + 0.5));
    2807         192 :         Float factor=0;
    2808         192 :         if(ixsub > 1){
    2809         960 :           for (Int k=0; k < ixsub/2; ++k)
    2810         768 :             factor= linear ? factor+(k+1): factor+sqrt(Float(k+1));
    2811             :           //factor= linear ? factor+(k+1): factor+(k+1)*(k+1)*(k+1);
    2812         192 :           factor *= 2.0;
    2813         192 :           if(linear)
    2814         192 :             nxsub=Int(floor((ceil(fabs(float(2*elcol+1-ixsub)/2.0))/factor)*nxp + 0.5));
    2815             :           else
    2816             :             //nxsub=Int(floor((ceil(fabs(float(2*elcol+1-ixsub)/2.0))*ceil(fabs(float(2*elcol+1-ixsub)/2.0))*ceil(fabs(float(2*elcol+1-ixsub)/2.0))/factor)*nxp + 0.5));
    2817           0 :             nxsub=Int(floor((sqrt(ceil(fabs(float(2*elcol+1-ixsub)/2.0)))/factor)*nxp + 0.5));
    2818             :         }
    2819             :         else{
    2820           0 :           nxsub=nxp;
    2821             :         }
    2822             :         //cerr << nxp << " col " << elcol << " nxsub " << nxsub << endl;
    2823         192 :         x0=minx;
    2824         192 :         elcol-=1;
    2825         864 :         while(elcol >= 0){
    2826             :           //x0+=Int(floor(((ceil(fabs(float(2*elcol+1-ixsub)/2.0))-1.0)*5 +1)*nxp/36.0+0.5));
    2827             : 
    2828         672 :           if(linear)
    2829         672 :             x0+=Int(floor((ceil(fabs(float(2*elcol+1-ixsub)/2.0))/factor)*nxp + 0.5));
    2830             :           else
    2831             :             //x0+=Int(floor((ceil(fabs(float(2*elcol+1-ixsub)/2.0))*ceil(fabs(float(2*elcol+1-ixsub)/2.0))*ceil(fabs(float(2*elcol+1-ixsub)/2.0))/factor)*nxp + 0.5));
    2832           0 :             x0+=Int(floor((sqrt(ceil(fabs(float(2*elcol+1-ixsub)/2.0)))/factor)*nxp + 0.5));
    2833         672 :           elcol-=1;
    2834             :         }
    2835         192 :         factor=0;
    2836         192 :         if(iysub >1){
    2837         960 :           for (Int k=0; k < iysub/2; ++k)
    2838             :             //factor=linear ? factor+(k+1): factor+(k+1)*(k+1)*(k+1);
    2839         768 :             factor= linear ? factor+(k+1): factor+sqrt(Float(k+1));
    2840         192 :           factor *= 2.0;
    2841             :           //nysub=Int(floor(((ceil(fabs(float(2*elrow+1-iysub)/2.0))-1.0)*5 +1)*nyp/36.0+0.5));
    2842         192 :           if(linear)
    2843         192 :             nysub=Int(floor((ceil(fabs(float(2*elrow+1-iysub)/2.0))/factor)*nyp + 0.5));
    2844             :           else
    2845           0 :             nysub=Int(floor((sqrt(ceil(fabs(float(2*elrow+1-iysub)/2.0)))/factor)*nyp + 0.5));
    2846             :         }
    2847             :         else{
    2848           0 :           nysub=nyp;
    2849             :         }
    2850             :           //nysub=Int(floor((ceil(fabs(float(2*elrow+1-iysub)/2.0))*ceil(fabs(float(2*elrow+1-iysub)/2.0))*ceil(fabs(float(2*elrow+1-iysub)/2.0))/factor)*nyp + 0.5));
    2851         192 :         y0=miny;
    2852         192 :         elrow-=1;
    2853             : 
    2854         864 :         while(elrow >=0){
    2855             :           //y0+=Int(floor(((ceil(fabs(float(2*elrow+1-iysub)/2.0))-1.0)*5 +1)*nyp/36.0+0.5));
    2856         672 :           if(linear)
    2857         672 :             y0+=Int(floor((ceil(fabs(float(2*elrow+1-iysub)/2.0))/factor)*nyp + 0.5));
    2858             :           else
    2859           0 :             y0+=Int(floor((sqrt(ceil(fabs(float(2*elrow+1-iysub)/2.0)))/factor)*nyp + 0.5));
    2860             :             //y0+=Int(floor((ceil(fabs(float(2*elrow+1-iysub)/2.0))*ceil(fabs(float(2*elrow+1-iysub)/2.0))*ceil(fabs(float(2*elrow+1-iysub)/2.0))/factor)*nyp + 0.5));
    2861         672 :           elrow-=1;
    2862             :         }
    2863             :       }
    2864         192 :       if( (y0+nysub) >= nyp){
    2865          24 :         nysub = nyp-y0-1;
    2866             :       }
    2867         192 :        if( (x0+nxsub) >= nxp){
    2868          24 :         nxsub = nxp-x0-1;
    2869             :       }
    2870         192 :       y0+=1;
    2871         192 :       x0+=1;
    2872             :       //cerr << icounter << " x0, y0 " << x0 << "  " << y0 << "  ixsub, iysub " <<  nxsub << "   " << nysub << endl;
    2873         192 :       if(doneThreadPartition_p < 0)
    2874           3 :         doneThreadPartition_p=1;
    2875             : 
    2876         192 : }
    2877             : 
    2878           0 :   void FTMachine::tweakGridSector(const Int& nx, const Int& ny, const Int& ixsub, const Int& iysub){
    2879             :     //if(doneThreadPartition_p)
    2880             :     //  return;
    2881           0 :     Vector<Int> x0, y0, nxsub, nysub;
    2882           0 :     Vector<Float> xcut(nx/2);
    2883           0 :     Vector<Float> ycut(ny/2);
    2884           0 :     if(griddedData2.nelements() >0 ){
    2885             :       //cerr << "shapes " << xcut.shape() << "   gd " << amplitude(griddedData2(IPosition(4, 0, ny/2-1, 0, 0), IPosition(4, nx/2-1, ny/2-1, 0,0))).shape() << endl;
    2886           0 :       convertArray(xcut, amplitude(griddedData2(IPosition(4, 0, ny/2-1, 0, 0), IPosition(4, nx/2-1, ny/2-1, 0,0))).reform(xcut.shape()));
    2887           0 :       convertArray(ycut, amplitude(griddedData2(IPosition(4, nx/2-1, 0, 0, 0), IPosition(4, nx/2-1, ny/2-1, 0,0))).reform(ycut.shape()));
    2888             :     }
    2889             :     else{
    2890           0 :       xcut=amplitude(griddedData(IPosition(4, 0, ny/2-1, 0, 0), IPosition(4, nx/2-1, ny/2-1, 0,0)));
    2891           0 :       ycut=amplitude(griddedData(IPosition(4, nx/2-1, 0, 0, 0), IPosition(4, nx/2-1, ny/2-1, 0,0)));
    2892             :     }
    2893             :     //cerr << griddedData2.shape() << "   " << griddedData.shape() << endl;
    2894           0 :     Vector<Float> cumSumX(nx/2, 0);
    2895             :     //Vector<Float> cumSumX2(nx/2,0);
    2896           0 :     cumSumX(0)=xcut(0);
    2897             :     //cumSumX2(0)=cumSumX(0)*cumSumX(0);
    2898           0 :     Float sumX=sum(xcut);
    2899           0 :     if(sumX==0.0)
    2900           0 :       return;
    2901             :     //cerr << "sumX " << sumX << endl;
    2902             :     //sumX *= sumX;
    2903           0 :     x0.resize(ixsub);
    2904           0 :     x0=nx/2-1;
    2905           0 :     nxsub.resize(ixsub);
    2906           0 :     nxsub=0;
    2907           0 :     x0(0)=0;
    2908           0 :     Int counter=1;
    2909           0 :     for (Int k=1; k < nx/2; ++k){
    2910           0 :       cumSumX(k)=cumSumX(k-1)+xcut(k);
    2911             :       //cumSumX2(k)=cumSumX(k)*cumSumX(k);
    2912           0 :       Float nextEdge=sumX/(Float(ixsub/2)*Float(ixsub/2))*Float(counter)*Float(counter);
    2913           0 :       if(cumSumX(k-1) < nextEdge && cumSumX(k) >= nextEdge){
    2914           0 :         x0(counter)=k;
    2915             :         //cerr << counter << "    "   << k << " diff " << x0(counter)-x0(counter-1) << endl;
    2916           0 :         nxsub(counter-1)=x0(counter)-x0(counter-1);
    2917           0 :         ++counter;
    2918             :       }
    2919             :     }
    2920             : 
    2921           0 :     x0(ixsub/2)=nx/2-1;
    2922           0 :     nxsub(ixsub/2)=nxsub(ixsub/2-1)=nx/2-1-x0(ixsub/2-1);
    2923           0 :     for(Int k=ixsub/2+1; k < ixsub; ++k){
    2924           0 :       x0(k)=x0(k-1)+ nxsub(ixsub-k);
    2925           0 :       nxsub(k)=nxsub(ixsub-k-1);
    2926             :     }
    2927           0 :     nxsub(ixsub-1)+=1;
    2928             : 
    2929           0 :     Vector<Float> cumSumY(ny/2, 0);
    2930             :     //Vector<Float> cumSumY2(ny/2,0);
    2931           0 :     cumSumY(0)=ycut(0);
    2932             :     //cumSumY2(0)=cumSumY(0)*cumSumY(0);
    2933           0 :     Float sumY=sum(ycut);
    2934           0 :     if(sumY==0.0)
    2935           0 :       return;
    2936             :     //sumY *=sumY;
    2937           0 :     y0.resize(iysub);
    2938           0 :     y0=ny/2-1;
    2939           0 :     nysub.resize(iysub);
    2940           0 :     nysub=0;
    2941           0 :     y0(0)=0;
    2942           0 :     counter=1;
    2943           0 :     for (Int k=1; k < ny/2; ++k){
    2944           0 :       cumSumY(k)=cumSumY(k-1)+ycut(k);
    2945             :       //cumSumY2(k)=cumSumY(k)*cumSumY(k);
    2946           0 :       Float nextEdge=sumY/(Float(iysub/2)*Float(iysub/2))*Float(counter)*Float(counter);
    2947           0 :       if(cumSumY(k-1) < nextEdge && cumSumY(k) >= nextEdge){
    2948           0 :         y0(counter)=k;
    2949           0 :         nysub(counter-1)=y0(counter)-y0(counter-1);
    2950           0 :         ++counter;
    2951             :       }
    2952             :     }
    2953             : 
    2954           0 :     y0(ixsub/2)=ny/2-1;
    2955           0 :     nysub(iysub/2)=nysub(iysub/2-1)=ny/2-1-y0(iysub/2-1);
    2956           0 :     for(Int k=iysub/2+1; k < iysub; ++k){
    2957           0 :       y0(k)=y0(k-1)+ nysub(iysub-k);
    2958           0 :       nysub(k)=nysub(iysub-k-1);
    2959             :     }
    2960           0 :     nysub(iysub-1)+=1;
    2961             : 
    2962           0 :     if(anyEQ(nxsub, 0) || anyEQ(nysub, 0))
    2963           0 :       return;
    2964             :     //cerr << " x0 " << x0 << "  nxsub " << nxsub << endl;
    2965             :     //cerr << " y0 " << y0 << "  nysub " << nysub << endl;
    2966           0 :     x0+=1;
    2967           0 :     y0+=1;
    2968           0 :     xsect_p.resize(ixsub*iysub);
    2969           0 :     ysect_p.resize(ixsub*iysub);
    2970           0 :     nxsect_p.resize(ixsub*iysub);
    2971           0 :     nysect_p.resize(ixsub*iysub);
    2972           0 :     for (Int iy=0; iy < iysub; ++iy){
    2973           0 :       for (Int ix=0; ix< ixsub; ++ix){
    2974             : 
    2975           0 :         xsect_p(iy*ixsub+ix)=x0[ix];
    2976           0 :         ysect_p(iy*ixsub+ix)=y0[iy];
    2977           0 :         nxsect_p(iy*ixsub+ix)=nxsub[ix];
    2978           0 :         nysect_p(iy*ixsub+ix)=nysub[iy];
    2979             :       }
    2980             :     }
    2981             : 
    2982           0 :     ++doneThreadPartition_p;
    2983             : 
    2984           0 :   }
    2985             : 
    2986             : 
    2987             :   /*
    2988             :   /// Move to individual FTMs............ make it pure virtual.
    2989             :   Bool FTMachine::useWeightImage()
    2990             :   {
    2991             :     if( name() == "GridFT" || name() == "WProjectFT" )
    2992             :       { return false; }
    2993             :     else
    2994             :       { return true; }
    2995             :   }
    2996             :   */
    2997             : 
    2998             :   }//# namespace refim ends
    2999             : }//namespace CASA ends
    3000             : 

Generated by: LCOV version 1.16