From 5b8eb9c6c41a95e93193c6173fdbf28a9cd6aec8 Mon Sep 17 00:00:00 2001
From: Ger van Diepen <diepen@astron.nl>
Date: Wed, 29 Sep 2010 13:55:25 +0000
Subject: [PATCH] bug 1436: Created a W-projection gridder that applies the
 corrections

---
 CEP/Imager/LofarGridder/CMakeLists.txt        |   7 +-
 .../include/LofarGridder/LofarGridder.h       |  95 ++++++-
 .../LofarGridder/LofarWProjectGridder.h       | 102 ++++++++
 CEP/Imager/LofarGridder/src/CMakeLists.txt    |   2 +-
 CEP/Imager/LofarGridder/src/LofarGridder.cc   | 135 ++++++++--
 .../LofarGridder/src/LofarWProjectGridder.cc  | 231 ++++++++++++++++++
 CEP/Imager/LofarGridder/src/Register.cc       |   5 +-
 CEP/Imager/LofarGridder/test/tLofarGridder.cc |   2 +-
 8 files changed, 545 insertions(+), 34 deletions(-)
 create mode 100644 CEP/Imager/LofarGridder/include/LofarGridder/LofarWProjectGridder.h
 create mode 100644 CEP/Imager/LofarGridder/src/LofarWProjectGridder.cc

diff --git a/CEP/Imager/LofarGridder/CMakeLists.txt b/CEP/Imager/LofarGridder/CMakeLists.txt
index de66fe92d19..09119a11735 100644
--- a/CEP/Imager/LofarGridder/CMakeLists.txt
+++ b/CEP/Imager/LofarGridder/CMakeLists.txt
@@ -1,9 +1,12 @@
 # $Id$
 
-lofar_package(LofarGridder 0.1 DEPENDS MWImager)
+#lofar_package(LofarGridder 0.1 DEPENDS MWImager)
+#lofar_package(LofarGridder 0.1 DEPENDS BBSKernel)
 
 lofar_find_package(AskapSoft REQUIRED)
-lofar_find_package(Casacore COMPONENTS images REQUIRED)
+lofar_find_package(LOFAR COMPONENTS bbskernel parmdb mwcommon blob common REQUIRED)
+lofar_find_package(Casacore COMPONENTS ms images REQUIRED)
+lofar_find_package(Boost REQUIRED)
 
 add_subdirectory(include/LofarGridder)
 add_subdirectory(src)
diff --git a/CEP/Imager/LofarGridder/include/LofarGridder/LofarGridder.h b/CEP/Imager/LofarGridder/include/LofarGridder/LofarGridder.h
index 6991ec0dd2b..460b94b7331 100644
--- a/CEP/Imager/LofarGridder/include/LofarGridder/LofarGridder.h
+++ b/CEP/Imager/LofarGridder/include/LofarGridder/LofarGridder.h
@@ -1,4 +1,4 @@
-//# LofarGridder.h: Test visibility gridder.
+//# LofarGridder.h: Gridder for LOFAR data correcting for DD effects
 //#
 //# Copyright (C) 2009
 //# ASTRON (Netherlands Institute for Radio Astronomy)
@@ -22,23 +22,26 @@
 //#
 //# @author Ger van Diepen <diepen at astron dot nl>
 
-#ifndef LOFAR_LOFARGRIDDER_TESTGRIDDER_H
-#define LOFAR_LOFARGRIDDER_TESTGRIDDER_H
+#ifndef LOFAR_LOFARGRIDDER_LOFARGRIDDER_H
+#define LOFAR_LOFARGRIDDER_LOFARGRIDDER_H
 
 #include <gridding/TableVisGridder.h>
 #include <Common/ParameterSet.h>
+#include <Common/lofar_vector.h>
+#include <Common/lofar_string.h>
 
 namespace LOFAR
 {
-  // @brief Gridder to test dynamic loading of gridders
+  // @brief Gridder for LOFAR data correcting for DD effects
   //
   // @ingroup testgridder
-  class LofarGridder : public askap::synthesis::TableVisGridder
+
+  class LofarGridder : public askap::synthesis::IVisGridder
   {
   public:
 
-    // Standard two dimensional box gridding
-    LofarGridder();
+    // Construct from the given parset.
+    explicit LofarGridder (const ParameterSet&);
 
     // Clone this Gridder
     virtual askap::synthesis::IVisGridder::ShPtr clone();
@@ -55,19 +58,89 @@ namespace LOFAR
     // @brief Register the gridder create function with its name.
     static void registerGridder();
 
+    // @brief Initialise the gridding
+    // @param axes axes specifications
+    // @param shape Shape of output image: u,v,pol,chan
+    // @param dopsf Make the psf?
+    virtual void initialiseGrid (const askap::scimath::Axes& axes,
+                                 const casa::IPosition& shape,
+                                 const bool dopsf=true);
+
+    // @brief Grid the visibility data.
+    // @param acc const data accessor to work with
+    // @note a non-const adapter is created behind the scene. If no on-the-fly
+    // visibility correction is performed, this adapter is equivalent to the
+    // original const data accessor.
+    virtual void grid (askap::synthesis::IConstDataAccessor& acc);
+      
+    // Form the final output image
+    // @param out Output double precision image or PSF
+    virtual void finaliseGrid (casa::Array<double>& out);
+
+    // @brief Calculate weights image
+    // @details Form the sum of the convolution function squared, 
+    // multiplied by the weights for each different convolution 
+    // function. This is used in the evaluation of the position
+    // dependent sensitivity
+    // @param out Output double precision sum of weights images
+    virtual void finaliseWeights (casa::Array<double>& out);
+
+    // @brief Initialise the degridding
+    // @param axes axes specifications
+    // @param image Input image: cube: u,v,pol,chan
+    virtual void initialiseDegrid (const askap::scimath::Axes& axes,
+                                   const casa::Array<double>& image);
+
+    // @brief Make context-dependant changes to the gridder behaviour
+    // @param context context
+    virtual void customiseForContext (casa::String context);
+      
+    // @brief assign weights
+    // @param viswt shared pointer to visibility weights
+    virtual void initVisWeights (askap::synthesis::IVisWeights::ShPtr viswt);
+      
+    // @brief Degrid the visibility data.
+    // @param[in] acc non-const data accessor to work with  
+    virtual void degrid (askap::synthesis::IDataAccessor& acc);
+
+    // @brief Finalise degridding.
+    virtual void finaliseDegrid();
+
     // @brief Initialise the indices
     // @param[in] acc const data accessor to work with
-    virtual void initIndices(const askap::synthesis::IConstDataAccessor& acc);
+    ///    virtual void initIndices (const askap::synthesis::IConstDataAccessor& acc);
 
     // @brief Correct for gridding convolution function
     // @param image image to be corrected
-    virtual void correctConvolution(casa::Array<double>& image);
+    ///    virtual void correctConvolution(casa::Array<double>& image);
 				
   protected:
     // Initialize convolution function
     // @param[in] acc const data accessor to work with
-    virtual void initConvolutionFunction
-    (const askap::synthesis::IConstDataAccessor& acc);
+    ///    virtual void initConvolutionFunction
+    ///    (const askap::synthesis::IConstDataAccessor& acc);
+
+  private:
+    // Initialize the corrections.
+    void initCorrections (const askap::synthesis::IConstDataAccessor& acc);
+
+
+    //# Data members.
+    // Is the gridder correction initialized?
+    bool itsInitialized;
+    // Nr of frequency channels to average.
+    uint itsFreqAvg;
+    // Nr of time slots to average.
+    uint itsTimeAvg;
+    // The effects to correct for.
+    vector<string> itsCorrect;
+    // The ParmDB to use.
+    string itsParmDBName;
+    // The gridder to use after correcting and averaging.
+    //# Unfortunatelty we need to use TableVisGridder because the
+    //# function getImageCntre is available only there.
+    askap::synthesis::IVisGridder::ShPtr itsIGridder;
+    askap::synthesis::TableVisGridder* itsGridder;
   };
 
 } //# end namespace
diff --git a/CEP/Imager/LofarGridder/include/LofarGridder/LofarWProjectGridder.h b/CEP/Imager/LofarGridder/include/LofarGridder/LofarWProjectGridder.h
new file mode 100644
index 00000000000..dfcf78b5e10
--- /dev/null
+++ b/CEP/Imager/LofarGridder/include/LofarGridder/LofarWProjectGridder.h
@@ -0,0 +1,102 @@
+//# LofarWProjectGridder.h: Gridder for LOFAR data correcting for DD effects
+//#
+//# Copyright (C) 2009
+//# ASTRON (Netherlands Institute for Radio Astronomy)
+//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+//#
+//# This file is part of the LOFAR software suite.
+//# The LOFAR software suite is free software: you can redistribute it and/or
+//# modify it under the terms of the GNU General Public License as published
+//# by the Free Software Foundation, either version 3 of the License, or
+//# (at your option) any later version.
+//#
+//# The LOFAR software suite is distributed in the hope that it will be useful,
+//# but WITHOUT ANY WARRANTY; without even the implied warranty of
+//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//# GNU General Public License for more details.
+//#
+//# You should have received a copy of the GNU General Public License along
+//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>.
+//#
+//# $Id$
+//#
+//# @author Ger van Diepen <diepen at astron dot nl>
+
+#ifndef LOFAR_LOFARGRIDDER_LOFARWPROJECTGRIDDER_H
+#define LOFAR_LOFARGRIDDER_LOFARWPROJECTGRIDDER_H
+
+//# LOFAR includes
+#include <BBSKernel/StationResponse.h>
+#include <Common/ParameterSet.h>
+#include <Common/lofar_vector.h>
+#include <Common/lofar_string.h>
+
+//# askap includes
+#include <gridding/WProjectVisGridder.h>
+
+//# casacore includes
+#include <ms/MeasurementSets/MeasurementSet.h>
+#include <casa/Quanta/MVDirection.h>
+
+namespace LOFAR
+{
+  // @brief Gridder for LOFAR data correcting for DD effects
+  //
+  // @ingroup testgridder
+
+  class LofarWProjectGridder : public askap::synthesis::WProjectVisGridder
+  {
+  public:
+
+    // Construct from the given parset.
+    explicit LofarWProjectGridder (const ParameterSet&);
+
+    // Clone this Gridder
+    virtual askap::synthesis::IVisGridder::ShPtr clone();
+
+    virtual ~LofarWProjectGridder();
+
+    // @brief Function to create the gridder from a parset.
+    // This function will be registered in the gridder registry.
+    static askap::synthesis::IVisGridder::ShPtr makeGridder
+    (const ParameterSet&);
+
+    // @brief Return the (unique) name of the gridder.
+    static const std::string& gridderName();
+
+    // @brief Register the gridder create function with its name.
+    static void registerGridder();
+
+  private:
+    // Correct the visibilities before gridding or after degridding.
+    void correctVisibilities (askap::synthesis::IDataAccessor& acc,
+                              bool forward);
+
+    // Initialize the corrections.
+    void initCorrections (const askap::synthesis::IConstDataAccessor& acc);
+
+    // Form an Instrument object.
+    BBS::Instrument makeInstrument (const casa::MeasurementSet& ms);
+
+
+    //# Data members.
+    // Is the gridder correction initialized?
+    bool itsInitialized;
+    // The ParmDB to use.
+    string itsParmDBName;
+    // The config file to use.
+    string itsConfigName;
+    string itsConfigPath;
+    // The StationResponse object to calculate the corrections.
+    BBS::StationResponse::Ptr itsResponse;
+    // Time and frequency interval in MS.
+    double itsTimeInterval;
+    double itsFreqInterval;
+    double itsStartFreq;
+    // The last facet center used.
+    casa::MVDirection itsLastFacetCenter;
+  };
+
+} //# end namespace
+
+#endif
diff --git a/CEP/Imager/LofarGridder/src/CMakeLists.txt b/CEP/Imager/LofarGridder/src/CMakeLists.txt
index c4da0604a08..cffa8da8d90 100644
--- a/CEP/Imager/LofarGridder/src/CMakeLists.txt
+++ b/CEP/Imager/LofarGridder/src/CMakeLists.txt
@@ -3,7 +3,7 @@
 include(LofarPackageVersion)
 
 lofar_add_library(lofargridder
-  Package__Version.cc Register.cc LofarGridder.cc
+  Package__Version.cc Register.cc LofarWProjectGridder.cc
   )
 
 lofar_add_bin_program(versionlofargridder versionlofargridder.cc)
diff --git a/CEP/Imager/LofarGridder/src/LofarGridder.cc b/CEP/Imager/LofarGridder/src/LofarGridder.cc
index a10700cc2f0..cb949611263 100644
--- a/CEP/Imager/LofarGridder/src/LofarGridder.cc
+++ b/CEP/Imager/LofarGridder/src/LofarGridder.cc
@@ -1,4 +1,4 @@
-//# TestGridder.cc: Test visibility gridder.
+//# LofarGridder.cc: Gridder for LOFAR data correcting for DD effects
 //#
 //# Copyright (C) 2009
 //# ASTRON (Netherlands Institute for Radio Astronomy)
@@ -22,31 +22,53 @@
 //#
 //# @author Ger van Diepen <diepen at astron dot nl>
 
+#include <lofar_config.h>
+#include <ParmDB/Grid.h>
 
+//# ASKAP includes
 #include <LofarGridder/LofarGridder.h>
 #include <gridding/VisGridderFactory.h>
+#include <dataaccess/TableConstDataAccessor.h>
+#include <dataaccess/TableConstDataIterator.h>
+#include <dataaccess/OnDemandBufferDataAccessor.h>
 
+//#casacore includes
+#include <tables/Tables/TableRecord.h>
+
+using namespace LOFAR::BBS;
+using namespace casa;
+using namespace askap;
 using namespace askap::synthesis;
 
 namespace LOFAR
 {
 
-  LofarGridder::LofarGridder()
-  {}
+  LofarGridder::LofarGridder (const ParameterSet& parset)
+    : itsInitialized (false)
+  {
+    itsTimeAvg = parset.getInt ("average.timestep", 1);
+    itsFreqAvg = parset.getInt ("average.freqstep", 1);
+    itsCorrect = parset.getStringVector ("correct");
+    itsParmDBName = parset.getString ("correct.parmdb");
+    string gridderName = parset.getString ("name");
+    itsIGridder = VisGridderFactory::createGridder (gridderName, parset);
+    itsGridder = dynamic_cast<TableVisGridder*>(itsIGridder.get());
+    ASSERT (itsGridder != 0);
+  }
 
   LofarGridder::~LofarGridder()
   {}
 
   // Clone a copy of this Gridder
-  IVisGridder::ShPtr LofarGridder::clone() 
+  IVisGridder::ShPtr LofarGridder::clone()
   {
     return IVisGridder::ShPtr(new LofarGridder(*this));
   }
 
-  IVisGridder::ShPtr LofarGridder::makeGridder (const ParameterSet&)
+  IVisGridder::ShPtr LofarGridder::makeGridder (const ParameterSet& parset)
   {
     std::cout << "LofarGridder::makeGridder" << std::endl;
-    return IVisGridder::ShPtr(new LofarGridder());
+    return IVisGridder::ShPtr(new LofarGridder(parset));
   }
 
   const std::string& LofarGridder::gridderName()
@@ -60,24 +82,103 @@ namespace LOFAR
     VisGridderFactory::registerGridder (gridderName(), &makeGridder);
   }
 
-  void LofarGridder::initIndices(const IConstDataAccessor&) 
+  void LofarGridder::initialiseGrid(const scimath::Axes& axes,
+                                    const casa::IPosition& shape,
+                                    const bool dopsf)
   {
+    itsGridder->initialiseGrid (axes, shape, dopsf);
   }
 
-  void LofarGridder::initConvolutionFunction(const IConstDataAccessor&)
+  void LofarGridder::grid(IConstDataAccessor& acc)
   {
-    itsSupport=0;
-    itsOverSample=1;
-    itsCSize=2*(itsSupport+1)*itsOverSample+1; // 3
-    itsCCenter=(itsCSize-1)/2; // 1
-    itsConvFunc.resize(1);
-    itsConvFunc[0].resize(itsCSize, itsCSize); // 3, 3, 1
-    itsConvFunc[0].set(0.0);
-    itsConvFunc[0](itsCCenter,itsCCenter)=1.0; // 1,1,0 = 1
+    if (! itsInitialized) {
+      initCorrections (acc);
+    }
+    // do correction, uvw rotation, and averaging here
+    // For time being only correction is done.
+    // It is possible to do the following:
+    ///  Array<Complex> data (acc.visibility());
+    // which makes a reference copy of the array, thus changs it later.
+    // This is an optimization we won't make yet.
+    // Can use PolConverter::isLinear() to check if data are XX,XY,YX,YY
+    OnDemandBufferDataAccessor acc2(acc);
+    Array<Complex>& data = acc2.rwVisibility();
+    itsGridder->grid (acc2);
+    // Get facet center in J2000.
+    casa::MVDirection center = itsGridder->getImageCentre();
+    double time = acc.time();    // time in sec (do I need exposure?)
+    const Vector<double>& freq = acc.frequency();
+    Axis::ShPtr timeAxis(new RegularAxis ());
+    Axis::ShPtr freqAxis(new RegularAxis ());
   }
+      
+  void LofarGridder::finaliseGrid(casa::Array<double>& out)
+  {
+    // If averaging is done, it has to grid the last timeslots.
+    itsGridder->finaliseGrid (out);
+  }
+
+  void LofarGridder::finaliseWeights(casa::Array<double>& out)
+  {
+    itsGridder->finaliseWeights (out);
+  }
+
+  void LofarGridder::initialiseDegrid(const scimath::Axes& axes,
+                                      const casa::Array<double>& image)
+  {
+    itsGridder->initialiseDegrid (axes, image);
+  }
+
+  void LofarGridder::customiseForContext(casa::String context)
+  {
+    itsGridder->customiseForContext (context);
+  }
+      
+  void LofarGridder::initVisWeights(IVisWeights::ShPtr viswt)
+  {
+    itsGridder->initVisWeights (viswt);
+  }
+      
+  void LofarGridder::degrid(IDataAccessor& acc)
+  {
+    if (! itsInitialized) {
+      initCorrections (acc);
+    }
+    // do correction, uvw rotation, and averaging here
+    // For time being only correction is done.
+    OnDemandBufferDataAccessor acc2(acc);
+    Array<Complex>& data = acc2.rwVisibility();
+    itsGridder->degrid (acc2);
+  }
+
+  void LofarGridder::finaliseDegrid()
+  {
+    itsGridder->finaliseDegrid();
+  }
+
+//   void LofarGridder::initIndices(const IConstDataAccessor& acc) 
+//   {
+//     itsGridder->initIndices (acc);
+//   }
+
+//   void LofarGridder::initConvolutionFunction(const IConstDataAccessor& acc)
+//   {
+//     itsGridder->initConvolutionFunction (acc);
+//   }
     
-  void LofarGridder::correctConvolution(casa::Array<double>& image)
+//   void LofarGridder::correctConvolution(casa::Array<double>& image)
+//   {
+//     itsGridder->correctConvolution (image);
+//   }
+
+  void LofarGridder::initCorrections (const IConstDataAccessor& acc)
   {
+    const TableConstDataAccessor& tacc =
+      dynamic_cast<const TableConstDataAccessor&>(acc);
+    const TableConstDataIterator& titer = tacc.iterator();
+    Table ms = titer.table();
+    Table antTab(ms.keywordSet().asTable("ANTENNA"));
+    itsInitialized = true;
   }
 
 } //# end namespace
diff --git a/CEP/Imager/LofarGridder/src/LofarWProjectGridder.cc b/CEP/Imager/LofarGridder/src/LofarWProjectGridder.cc
new file mode 100644
index 00000000000..f0b68ab3096
--- /dev/null
+++ b/CEP/Imager/LofarGridder/src/LofarWProjectGridder.cc
@@ -0,0 +1,231 @@
+//# LofarWProjectGridder.cc: WProjection gridder for LOFAR data correcting for DD effects
+//#
+//# Copyright (C) 2010
+//# ASTRON (Netherlands Institute for Radio Astronomy)
+//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+//#
+//# This file is part of the LOFAR software suite.
+//# The LOFAR software suite is free software: you can redistribute it and/or
+//# modify it under the terms of the GNU General Public License as published
+//# by the Free Software Foundation, either version 3 of the License, or
+//# (at your option) any later version.
+//#
+//# The LOFAR software suite is distributed in the hope that it will be useful,
+//# but WITHOUT ANY WARRANTY; without even the implied warranty of
+//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//# GNU General Public License for more details.
+//#
+//# You should have received a copy of the GNU General Public License along
+//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>.
+//#
+//# $Id$
+//#
+//# @author Ger van Diepen <diepen at astron dot nl>
+
+#include <lofar_config.h>
+#include <ParmDB/Grid.h>
+
+//# ASKAP includes
+#include <LofarGridder/LofarWProjectGridder.h>
+#include <gridding/VisGridderFactory.h>
+#include <dataaccess/TableConstDataAccessor.h>
+#include <dataaccess/TableConstDataIterator.h>
+
+//# casacore includes
+#include <tables/Tables/TableRecord.h>
+#include <ms/MeasurementSets/MSColumns.h>
+#include <ms/MeasurementSets/MSSpWindowColumns.h>
+#include <ms/MeasurementSets/MSAntennaColumns.h>
+#include <ms/MeasurementSets/MSObsColumns.h>
+#include <measures/Measures/MeasTable.h>
+#include <casa/OS/Path.h>
+
+using namespace LOFAR::BBS;
+using namespace casa;
+using namespace askap;
+using namespace askap::synthesis;
+
+namespace LOFAR
+{
+
+  LofarWProjectGridder::LofarWProjectGridder (const ParameterSet& parset)
+    : WProjectVisGridder (*(dynamic_cast<const WProjectVisGridder*>
+                            (WProjectVisGridder::createGridder(parset).get()))),
+      itsInitialized (false)
+  {
+    // Currently only beam can be corrected for.
+    ///    itsTimeAvg = parset.getInt ("average.timestep", 1);
+    ///    itsFreqAvg = parset.getInt ("average.freqstep", 1);
+    ///    itsCorrect = parset.getStringVector ("correct");
+    itsParmDBName = parset.getString ("ParmDB.Instrument", "");
+    itsConfigName = parset.getString ("Beam.StationConfig.Name");
+    itsConfigPath = parset.getString ("Beam.StationConfig.Path");
+  }
+
+  LofarWProjectGridder::~LofarWProjectGridder()
+  {}
+
+  // Clone a copy of this Gridder
+  IVisGridder::ShPtr LofarWProjectGridder::clone()
+  {
+    return IVisGridder::ShPtr(new LofarWProjectGridder(*this));
+  }
+
+  IVisGridder::ShPtr LofarWProjectGridder::makeGridder
+  (const ParameterSet& parset)
+  {
+    std::cout << "LofarWProjectGridder::makeGridder" << std::endl;
+    return IVisGridder::ShPtr(new LofarWProjectGridder(parset));
+  }
+
+  const std::string& LofarWProjectGridder::gridderName()
+  {
+    static std::string name("LofarGridder.WProject");
+    return name;
+  }
+
+  void LofarWProjectGridder::registerGridder()
+  {
+    VisGridderFactory::registerGridder (gridderName(), &makeGridder);
+  }
+
+  void LofarWProjectGridder::correctVisibilities (IDataAccessor& acc,
+                                                  bool forward)
+  {
+    if (!itsInitialized) {
+      initCorrections (acc);
+    }
+    // If changed, set the facet center as direction of interest.
+    MVDirection facetCenter = getImageCentre();
+    if (facetCenter != itsLastFacetCenter) {
+      itsLastFacetCenter = facetCenter;
+      itsResponse->setDirection (MDirection(facetCenter, MDirection::J2000));
+    }
+    // Get read/write access to the visibilities. It makes a copy if needed.
+    Array<Complex>& visData = acc.rwVisibility();
+    ASSERT (visData.contiguousStorage());
+    Complex* data = visData.data();
+    uInt nfreq = visData.shape()[1];
+    double time = acc.time();
+    // Set the axes for the BBS request.
+    Axis::ShPtr freqAxis
+      (new RegularAxis(itsStartFreq-itsFreqInterval/2, itsFreqInterval, nfreq));
+    Axis::ShPtr timeAxis
+      (new RegularAxis(time-itsTimeInterval/2, itsTimeInterval, 1));
+    Grid grid(timeAxis, freqAxis);
+    itsResponse->setEvalGrid (grid);
+    const casa::Vector<uInt>& ant1 = acc.antenna1();
+    const casa::Vector<uInt>& ant2 = acc.antenna2();
+    for (uInt i=0; i<ant1.size(); ++i) {
+      JonesMatrix::View j1 = itsResponse->evaluate (ant1[i]);
+      JonesMatrix::View j2 = itsResponse->evaluate (ant2[i]);
+      for (uInt j=0; j<nfreq; ++j) {
+        dcomplex cl0 = j1(j,0).getDComplex(0,0);
+        dcomplex cl1 = j1(j,0).getDComplex(1,0);
+        dcomplex cl2 = j1(j,0).getDComplex(0,1);
+        dcomplex cl3 = j1(j,0).getDComplex(1,1);
+        dcomplex cr0 = conj (j2(j,0).getDComplex(0,0));
+        dcomplex cr1 = conj (j2(j,0).getDComplex(1,0));
+        dcomplex cr2 = conj (j2(j,0).getDComplex(0,1));
+        dcomplex cr3 = conj (j2(j,0).getDComplex(1,1));
+        dcomplex d0 = data[0];
+        dcomplex d1 = data[1];
+        dcomplex d2 = data[2];
+        dcomplex d3 = data[3];
+        if (forward) {
+          // For gridding use inverse of responses.
+          //   data = inv(res(i)) * data * inv(conjtranspose(res(j)))
+          // Note that inv(conjtranspose(A)) == conjtranspose(inv(A))
+          // inv(a b) == ( d -b)  / (ad-bc)
+          //    (c d)    (-c  a)
+          dcomplex tmp0 = cl3*d0 - cl1*d2;
+          dcomplex tmp1 = cl3*d1 - cl1*d3;
+          dcomplex tmp2 = cl0*d2 - cl2*d0;
+          dcomplex tmp3 = cl0*d3 - cl2*d1;
+          dcomplex factor = 1. / ((cl0*cl3 - cl1*cl2) * (cr0*cr3 - cr1*cr2));
+          data[0] = factor * (tmp0*cr3 - tmp1*cr1);
+          data[1] = factor * (tmp1*cr0 - tmp0*cr2);
+          data[2] = factor * (tmp2*cr3 - tmp3*cr1);
+          data[3] = factor * (tmp3*cr0 - tmp2*cr2);
+        } else {
+          // Degridding; data = res(i) * data * conjtranspose(res(j))
+          dcomplex tmp0 = cl0*d0 + cl1*d2;
+          dcomplex tmp1 = cl0*d1 + cl1*d3;
+          dcomplex tmp2 = cl2*d0 + cl3*d2;
+          dcomplex tmp3 = cl2*d1 + cl3*d3;
+          data[0] = tmp0*cr0 + tmp1*cr1;
+          data[1] = tmp0*cr2 + tmp1*cr3;
+          data[2] = tmp2*cr0 + tmp3*cr1;
+          data[3] = tmp2*cr2 + tmp3*cr3;
+        }
+        data += 4;
+      }
+    }
+  }
+
+  void LofarWProjectGridder::initCorrections (const IConstDataAccessor& acc)
+  {
+    // Ensure there are polarizations XX,XY,YX,YY.
+    ASSERT (acc.stokes().size() == 4);
+    ASSERT (acc.stokes()[0] == Stokes::XX);
+    ASSERT (acc.stokes()[1] == Stokes::XY);
+    ASSERT (acc.stokes()[2] == Stokes::YX);
+    ASSERT (acc.stokes()[3] == Stokes::YY);
+    const TableConstDataAccessor& tacc =
+      dynamic_cast<const TableConstDataAccessor&>(acc);
+    const TableConstDataIterator& titer = tacc.iterator();
+    MeasurementSet ms(titer.table());
+    // Get the time interval.
+    ROMSColumns msCol(ms);
+    // Get the reference frequency and width.
+    // It assumes that the interval is constant for this band.
+    ROMSSpWindowColumns spwCols(ms.spectralWindow());
+    double refFreq = spwCols.refFrequency()(0);
+    itsFreqInterval = spwCols.chanWidth()(0).data()[0];
+    casa::Vector<double> freqs = spwCols.chanFreq()(0);
+    itsStartFreq = freqs[0];
+    for (uInt i=1; i<freqs.size(); ++i) {
+      ASSERTSTR (casa::near(freqs[i], itsStartFreq + i*itsFreqInterval),
+                 "Frequency channels are not regularly spaced");
+    }
+    // Form the StationResponse object.
+    itsResponse = StationResponse::Ptr (new StationResponse
+                                        (makeInstrument(ms),
+                                         itsConfigName, Path(itsConfigPath),
+                                         refFreq));
+    // Set the pointing direction (for beamforming).
+    // Use first value of MDirection array in first row in FIELD subtable.
+    ROMSFieldColumns fieldCols(ms.field());
+    itsResponse->setPointing (fieldCols.delayDirMeasCol()(0).data()[0]);
+    itsTimeInterval = msCol.interval()(0);
+    // Initialization is done.
+    itsInitialized = true;
+  }
+
+  BBS::Instrument LofarWProjectGridder::makeInstrument
+  (const MeasurementSet& ms)
+  {
+    // Get all station positions.
+    ROMSAntennaColumns antCols(ms.antenna());
+    vector<Station> stations;
+    stations.reserve (ms.antenna().nrow());
+    for (uInt i=0; i<ms.antenna().nrow(); ++i) {
+      stations.push_back (Station(antCols.name()(i),
+                                  antCols.positionMeas()(i)));
+    }
+    // Find observatory position.
+    // If not found, set it to the position of the middle station.
+    MPosition arrayPos;
+    Bool fndObs = False;
+    if (ms.observation().nrow() > 0) {
+      ROMSObservationColumns obsCols(ms.observation());
+      String telescope = obsCols.telescopeName()(0);
+      fndObs = MeasTable::Observatory (arrayPos, telescope);
+    }
+    if (!fndObs  &&  stations.size() > 0) {
+      arrayPos = stations[stations.size()/2].position();
+    }
+    return BBS::Instrument ("LOFAR", arrayPos, stations);
+  }
+
+} //# end namespace
diff --git a/CEP/Imager/LofarGridder/src/Register.cc b/CEP/Imager/LofarGridder/src/Register.cc
index 51b68814d2c..a8c1fd99429 100644
--- a/CEP/Imager/LofarGridder/src/Register.cc
+++ b/CEP/Imager/LofarGridder/src/Register.cc
@@ -23,10 +23,11 @@
 //# @author Ger van Diepen <diepen at astron dot nl>
 
 //# Includes
+#include <lofar_config.h>
 #include <LofarGridder/Register.h>
-#include <LofarGridder/LofarGridder.h>
+#include <LofarGridder/LofarWProjectGridder.h>
 
 void register_lofargridder()
 {
-  LOFAR::LofarGridder::registerGridder();
+  LOFAR::LofarWProjectGridder::registerGridder();
 }
diff --git a/CEP/Imager/LofarGridder/test/tLofarGridder.cc b/CEP/Imager/LofarGridder/test/tLofarGridder.cc
index 23e3cb68c94..1abe5b717b1 100644
--- a/CEP/Imager/LofarGridder/test/tLofarGridder.cc
+++ b/CEP/Imager/LofarGridder/test/tLofarGridder.cc
@@ -37,7 +37,7 @@ int main (int argc, const char** argv)
 
     // Create a LofarGridder instance.
     ParameterSet parset;
-    parset.add ("gridder", "LofarGridder");
+    parset.add ("gridder", "LofarGridder.WProject");
     IVisGridder::ShPtr gridder = VisGridderFactory::make (parset);
 
   } catch (const std::exception& x) {
-- 
GitLab