LCOV - code coverage report
Current view: top level - synthesis/TransformMachines2 - FTMachine.cc (source / functions) Hit Total Coverage
Test: ctest_coverage.info Lines: 962 1551 62.0 %
Date: 2023-11-06 10:06:49 Functions: 45 70 64.3 %

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

Generated by: LCOV version 1.16