From 047e805bcf8fa89aadf76bab8e46747fec0f2a80 Mon Sep 17 00:00:00 2001
From: Joris van Zwieten <zwieten@astron.nl>
Date: Mon, 30 Jul 2012 13:11:37 +0000
Subject: [PATCH] Task #3223: Cleaned up Demixer.cc, removed boost::multi_array
 dependency, several other source files cleaned up and documented.

---
 .gitattributes                                |   2 +
 CEP/DP3/DPPP/include/DPPP/BBSExpr.h           | 111 ---
 CEP/DP3/DPPP/include/DPPP/CMakeLists.txt      |   2 +-
 CEP/DP3/DPPP/include/DPPP/Demixer.h           |  59 +-
 CEP/DP3/DPPP/include/DPPP/EstimateMixed.h     |   2 +-
 .../DPPP/include/DPPP/ModelComponentVisitor.h |   2 -
 CEP/DP3/DPPP/include/DPPP/Patch.h             |  18 +-
 CEP/DP3/DPPP/include/DPPP/PointSource.h       |   9 +-
 CEP/DP3/DPPP/include/DPPP/Simulator.h         |  75 ++
 CEP/DP3/DPPP/src/Apply.cc                     |  85 +-
 CEP/DP3/DPPP/src/BBSExpr.cc                   | 221 -----
 CEP/DP3/DPPP/src/CMakeLists.txt               |   2 +-
 CEP/DP3/DPPP/src/Demixer.cc                   | 804 ++++++++----------
 CEP/DP3/DPPP/src/EstimateMixed.cc             | 324 ++++---
 CEP/DP3/DPPP/src/Patch.cc                     |  43 +-
 CEP/DP3/DPPP/src/PhaseShift.cc                |  48 +-
 CEP/DP3/DPPP/src/PointSource.cc               |  21 +-
 CEP/DP3/DPPP/src/Simulate.cc                  | 475 ++++-------
 CEP/DP3/DPPP/src/Simulator.cc                 | 304 +++++++
 CEP/DP3/DPPP/src/SourceDBUtil.cc              |   5 +-
 CEP/DP3/DPPP/src/SubtractMixed.cc             |   5 +-
 21 files changed, 1160 insertions(+), 1457 deletions(-)
 delete mode 100644 CEP/DP3/DPPP/include/DPPP/BBSExpr.h
 create mode 100644 CEP/DP3/DPPP/include/DPPP/Simulator.h
 delete mode 100644 CEP/DP3/DPPP/src/BBSExpr.cc
 create mode 100644 CEP/DP3/DPPP/src/Simulator.cc

diff --git a/.gitattributes b/.gitattributes
index 38185193884..26ba1a72404 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -736,6 +736,7 @@ CEP/DP3/DPPP/include/DPPP/PointSource.h -text
 CEP/DP3/DPPP/include/DPPP/Position.h -text
 CEP/DP3/DPPP/include/DPPP/RunDetails.h -text
 CEP/DP3/DPPP/include/DPPP/Simulate.h -text
+CEP/DP3/DPPP/include/DPPP/Simulator.h -text
 CEP/DP3/DPPP/include/DPPP/SourceDBUtil.h -text
 CEP/DP3/DPPP/include/DPPP/Stokes.h -text
 CEP/DP3/DPPP/include/DPPP/SubtractMixed.h -text
@@ -763,6 +764,7 @@ CEP/DP3/DPPP/src/PointSource.cc -text
 CEP/DP3/DPPP/src/Position.cc -text
 CEP/DP3/DPPP/src/RunDetails.cc -text
 CEP/DP3/DPPP/src/Simulate.cc -text
+CEP/DP3/DPPP/src/Simulator.cc -text
 CEP/DP3/DPPP/src/SourceDBUtil.cc -text
 CEP/DP3/DPPP/src/Stokes.cc -text
 CEP/DP3/DPPP/src/SubtractMixed.cc -text
diff --git a/CEP/DP3/DPPP/include/DPPP/BBSExpr.h b/CEP/DP3/DPPP/include/DPPP/BBSExpr.h
deleted file mode 100644
index 756c17114ed..00000000000
--- a/CEP/DP3/DPPP/include/DPPP/BBSExpr.h
+++ /dev/null
@@ -1,111 +0,0 @@
-//# BBSExpr.h: Create the expression tree for BBS
-//#
-//# Copyright (C) 2012
-//# 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$
-
-#ifndef DPPP_BBSEXPR_H
-#define DPPP_BBSEXPR_H
-
-// \file
-// Predict visibilities given a source model
-
-#include <DPPP/DPBuffer.h>
-#include <DPPP/DPInfo.h>
-#include <DPPP/DPInput.h>
-
-#include <BBSKernel/MeasurementExprLOFAR.h>
-#include <BBSKernel/CorrelationMask.h>
-#include <BBSKernel/ParmManager.h>
-#include <BBSKernel/VisBuffer.h>
-#include <BBSKernel/Estimate.h>
-#include <ParmDB/SourceDB.h>
-#include <ParmDB/Grid.h>
-
-#include <Common/lofar_vector.h>
-#include <Common/lofar_string.h>
-
-namespace LOFAR {
-  namespace DPPP {
-
-    // \addtogroup NDPPP
-    // @{
-
-    class BBSExpr
-    {
-    public:
-      // Construct the expression for the given sky and instrument
-      // parameter databases.
-      BBSExpr (const DPInfo& info, const string& skyName,
-               const string& instrumentName, double elevationCutoff);
-
-      ~BBSExpr();
-
-      // Set the options.
-      void setOptions (const BBS::SolverOptions&);
-
-      // Add a model expression for the given source and phase reference.
-      void addModel (const string& source, const casa::MDirection& phaseRef);
-
-      // Estimate the model parameters.
-      void estimate (vector<vector<DPBuffer> >& buffers,
-                     const BBS::Grid& visGrid, const BBS::Grid& solveGrid,
-                     const vector<casa::Array<casa::DComplex> >& factors);
-
-      // Subtract the sources.
-      void subtract (vector<DPBuffer>& buffer, const BBS::Grid& visGrid,
-                     const vector<casa::Array<casa::DComplex> >& factors,
-                     uint target, uint nSources);
-
-    private:
-      // For now, forbid copy construction and assignment.
-      BBSExpr(const BBSExpr& other);
-      BBSExpr& operator= (const BBSExpr& other);
-
-      // Clear the solvables in the model expressions.
-      void clearSolvables();
-
-      // Set the solvables in the model expressions to the gains.
-      void setSolvables();
-
-      // Gather information about the instrument from the input meta-data.
-      void initInstrument(const DPInfo& info);
-
-      //# Data members
-      boost::shared_ptr<BBS::SourceDB>  itsSourceDB;
-      vector<BBS::MeasurementExpr::Ptr> itsModels;
-      BBS::Instrument::Ptr              itsInstrument;
-      casa::MDirection                  itsDelayRef;
-      casa::MDirection                  itsTileRef;
-      BBS::BaselineSeq                  itsBaselines;
-      BBS::CorrelationSeq               itsCorrelations;
-      BBS::BaselineMask                 itsBaselineMask;
-      BBS::CorrelationMask              itsCorrelationMask;
-      double                            itsElevationCutoff;
-      BBS::EstimateOptions              itsOptions;
-      BBS::ParmGroup                    itsParms;
-      vector<BBS::ParmGroup>            itsModelParms;
-    };
-
-// @}
-
-  } //# namespace DPPP
-} //# namespace LOFAR
-
-#endif
diff --git a/CEP/DP3/DPPP/include/DPPP/CMakeLists.txt b/CEP/DP3/DPPP/include/DPPP/CMakeLists.txt
index c46e3612d82..5ecc418523b 100644
--- a/CEP/DP3/DPPP/include/DPPP/CMakeLists.txt
+++ b/CEP/DP3/DPPP/include/DPPP/CMakeLists.txt
@@ -10,7 +10,7 @@ set(inst_HEADERS
   StationAdder.h Filter.h
   PhaseShift.h Demixer.h
   Cursor.h CursorUtilCasa.h Position.h Stokes.h SourceDBUtil.h
-  Apply.h EstimateMixed.h Simulate.h SubtractMixed.h Baseline.h
+  Apply.h EstimateMixed.h Simulate.h Simulator.h SubtractMixed.h Baseline.h
   ModelComponent.h PointSource.h GaussianSource.h Patch.h
   ModelComponentVisitor.h
   FlaggerStatistics.h)
diff --git a/CEP/DP3/DPPP/include/DPPP/Demixer.h b/CEP/DP3/DPPP/include/DPPP/Demixer.h
index 5be55300e1d..d001f699b25 100644
--- a/CEP/DP3/DPPP/include/DPPP/Demixer.h
+++ b/CEP/DP3/DPPP/include/DPPP/Demixer.h
@@ -69,8 +69,6 @@ namespace LOFAR {
       // Parameters are obtained from the parset using the given prefix.
       Demixer (DPInput*, const ParSet&, const string& prefix);
 
-      virtual ~Demixer();
-
       // Process the data.
       // It keeps the data.
       // When processed, it invokes the process function of the next step.
@@ -92,11 +90,6 @@ namespace LOFAR {
       virtual void showTimings (std::ostream&, double duration) const;
 
     private:
-      void initUnknowns();
-
-      // Solve gains and subtract sources.
-      void demix();
-
       // Add the decorrelation factor contribution for each time slot.
       void addFactors (const DPBuffer& newBuf,
                        casa::Array<casa::DComplex>& factorBuf);
@@ -114,18 +107,8 @@ namespace LOFAR {
                       vector<MultiResultStep*> avgResults,
                       uint resultIndex);
 
-      // Calculate the P matrix telling how to deal with sources that will
-      // not be predicted.
-      // Those sources are the last columns in the demixing matrix.
-      vector<casa::Array<casa::DComplex> > getP
-      (const vector<casa::Array<casa::DComplex> >& factors, uint nsources);
-
-      // Convert a double value to a string (with sufficient precision).
-      string toString (double value) const;
-
-      // Convert a angle string with an optional unit to radians.
-      // The default input unit is degrees.
-      double getAngle (const casa::String& value) const;
+      // Solve gains and subtract sources.
+      void demix();
 
       // Export the solutions to a ParmDB.
       void dumpSolutions();
@@ -149,22 +132,24 @@ namespace LOFAR {
       vector<string>                        itsModelSources;
       vector<string>                        itsExtraSources;
       vector<string>                        itsAllSources;
-//      vector<uint>                          itsCutOffs;
+//      vector<double>                        itsCutOffs;
       uint                                  itsNDir;
       uint                                  itsNModel;
+      uint                                  itsNStation;
       uint                                  itsNBl;
       uint                                  itsNCorr;
       uint                                  itsNChanIn;
       uint                                  itsNTimeIn;
-      uint                                  itsNChanOutSubtr;
+      uint                                  itsNTimeDemix;
       uint                                  itsNChanAvgSubtr;
       uint                                  itsNTimeAvgSubtr;
-      uint                                  itsNTimeChunkSubtr;
+      uint                                  itsNChanOutSubtr;
       uint                                  itsNTimeOutSubtr;
-      uint                                  itsNChanOut;
+      uint                                  itsNTimeChunk;
+      uint                                  itsNTimeChunkSubtr;
       uint                                  itsNChanAvg;
       uint                                  itsNTimeAvg;
-      uint                                  itsNTimeChunk;
+      uint                                  itsNChanOut;
       uint                                  itsNTimeOut;
       double                                itsTimeIntervalAvg;
 
@@ -186,26 +171,22 @@ namespace LOFAR {
       //# shape #directions x #directions.
       vector<casa::Array<casa::DComplex> >  itsFactorsSubtr;
 
+      PatchList                             itsPatchList;
+      Position                              itsPhaseRef;
+      vector<Baseline>                      itsBaselines;
+      casa::Vector<double>                  itsFreqDemix;
+      casa::Vector<double>                  itsFreqSubtr;
+      vector<double>                        itsUnknowns;
+      vector<double>                        itsLastKnowns;
+      uint                                  itsTimeIndex;
+      uint                                  itsNConverged;
+
       //# Timers.
       NSTimer                               itsTimer;
       NSTimer                               itsTimerPhaseShift;
       NSTimer                               itsTimerDemix;
       NSTimer                               itsTimerSolve;
-
-      uint                                  itsNConverged;
-      uint                                  itsTimeCount;
-      PatchList                             itsPatchList;
-      vector<Baseline>                      itsBaselines;
-      casa::Vector<double>                  itsFreqDemix;
-      casa::Vector<double>                  itsFreqSubtr;
-      uint                                  itsNTimeDemix;
-      uint                                  itsNStation;
-      Position                              itsPhaseRef;
-      casa::Array<double>                   itsUnknowns;
-//      casa::Array<double>                   itsErrors;
-      casa::Array<double>                   itsLastKnowns;
-//      vector<casa::MeasFrame>               itsFrames;
-//      vector<casa::MDirection::Convert>     itsConverters;
+      NSTimer                               itsTimerDump;
     };
 
   } //# end namespace
diff --git a/CEP/DP3/DPPP/include/DPPP/EstimateMixed.h b/CEP/DP3/DPPP/include/DPPP/EstimateMixed.h
index 5a0a85abed0..10105f04341 100644
--- a/CEP/DP3/DPPP/include/DPPP/EstimateMixed.h
+++ b/CEP/DP3/DPPP/include/DPPP/EstimateMixed.h
@@ -84,7 +84,7 @@ bool estimate(size_t nDirection, size_t nStation, size_t nBaseline,
     size_t nChannel, const_cursor<Baseline> baselines,
     vector<const_cursor<fcomplex> > data, vector<const_cursor<dcomplex> > model,
     const_cursor<bool> flag, const_cursor<float> weight,
-    const_cursor<dcomplex> mix, double *unknowns, double *errors);
+    const_cursor<dcomplex> mix, double *unknowns);
 // @}
 
 } //# namespace DPPP
diff --git a/CEP/DP3/DPPP/include/DPPP/ModelComponentVisitor.h b/CEP/DP3/DPPP/include/DPPP/ModelComponentVisitor.h
index c09aab84973..c45857cd0f9 100644
--- a/CEP/DP3/DPPP/include/DPPP/ModelComponentVisitor.h
+++ b/CEP/DP3/DPPP/include/DPPP/ModelComponentVisitor.h
@@ -34,7 +34,6 @@ namespace DPPP
 
 class PointSource;
 class GaussianSource;
-class Patch;
 
 // \addtogroup NDPPP
 // @{
@@ -46,7 +45,6 @@ public:
 
     virtual void visit(const PointSource&) = 0;
     virtual void visit(const GaussianSource&) = 0;
-    virtual void visit(const Patch&) = 0;
 };
 
 // @}
diff --git a/CEP/DP3/DPPP/include/DPPP/Patch.h b/CEP/DP3/DPPP/include/DPPP/Patch.h
index b77a0611444..a1494be23c7 100644
--- a/CEP/DP3/DPPP/include/DPPP/Patch.h
+++ b/CEP/DP3/DPPP/include/DPPP/Patch.h
@@ -41,7 +41,7 @@ namespace DPPP
 // \addtogroup NDPPP
 // @{
 
-class Patch: public ModelComponent
+class Patch
 {
 public:
     typedef shared_ptr<Patch>       Ptr;
@@ -52,11 +52,12 @@ public:
 
     const string &name() const;
     virtual const Position &position() const;
-    virtual void accept(ModelComponentVisitor &visitor) const;
+
+    size_t nComponents() const;
+    ModelComponent::ConstPtr component(size_t i) const;
 
 private:
     typedef vector<ModelComponent::ConstPtr>::const_iterator const_iterator;
-
     const_iterator begin() const;
     const_iterator end() const;
 
@@ -92,6 +93,17 @@ inline const Position &Patch::position() const
     return itsPosition;
 }
 
+inline size_t Patch::nComponents() const
+{
+    return itsComponents.size();
+}
+
+inline ModelComponent::ConstPtr Patch::component(size_t i) const
+{
+    return itsComponents[i];
+}
+
+
 } //# namespace DPPP
 } //# namespace LOFAR
 
diff --git a/CEP/DP3/DPPP/include/DPPP/PointSource.h b/CEP/DP3/DPPP/include/DPPP/PointSource.h
index 00e1ea2f755..f3e9fe0e60e 100644
--- a/CEP/DP3/DPPP/include/DPPP/PointSource.h
+++ b/CEP/DP3/DPPP/include/DPPP/PointSource.h
@@ -38,8 +38,6 @@ namespace LOFAR
 namespace DPPP
 {
 
-class ModelComponentVisitor;
-
 // \addtogroup NDPPP
 // @{
 
@@ -60,11 +58,7 @@ public:
     template <typename T>
     void setSpectralIndex(double refFreq, T first, T last);
 
-    void setPolarizedFraction(double fraction);
-
-    void setPolarizationAngle(double angle);
-
-    void setRotationMeasure(double rm);
+    void setRotationMeasure(double fraction, double angle, double rm);
 
     Stokes stokes(double freq) const;
 
@@ -81,6 +75,7 @@ private:
     double          itsPolarizedFraction;
     double          itsPolarizationAngle;
     double          itsRotationMeasure;
+    bool            itsHasRotationMeasure;
 };
 
 // @}
diff --git a/CEP/DP3/DPPP/include/DPPP/Simulator.h b/CEP/DP3/DPPP/include/DPPP/Simulator.h
new file mode 100644
index 00000000000..b4a5b2aeaea
--- /dev/null
+++ b/CEP/DP3/DPPP/include/DPPP/Simulator.h
@@ -0,0 +1,75 @@
+//# Simulator.h: Compute visibilities for different model components types
+//# (implementation of ModelComponentVisitor).
+//#
+//# Copyright (C) 2012
+//# 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$
+
+#ifndef DPPP_SIMULATOR_H
+#define DPPP_SIMULATOR_H
+
+// \file
+// Compute visibilities for different model components types (implementation of
+// ModelComponentVisitor).
+
+#include <DPPP/Baseline.h>
+#include <DPPP/Cursor.h>
+#include <DPPP/ModelComponent.h>
+#include <DPPP/ModelComponentVisitor.h>
+#include <DPPP/Position.h>
+#include <Common/lofar_complex.h>
+#include <Common/lofar_vector.h>
+
+namespace LOFAR
+{
+namespace DPPP
+{
+
+// \addtogroup NDPPP
+// @{
+
+class Simulator: public ModelComponentVisitor
+{
+public:
+    Simulator(const Position &reference, size_t nStation, size_t nBaseline,
+        size_t nChannel, const_cursor<Baseline> baselines,
+        const_cursor<double> freq, const_cursor<double> uvw,
+        cursor<dcomplex> buffer);
+
+    void simulate(const ModelComponent::ConstPtr &component);
+
+private:
+    virtual void visit(const PointSource &component);
+    virtual void visit(const GaussianSource &component);
+
+private:
+    Position                itsReference;
+    size_t                  itsNStation, itsNBaseline, itsNChannel;
+    const_cursor<Baseline>  itsBaselines;
+    const_cursor<double>    itsFreq, itsUVW;
+    cursor<dcomplex>        itsBuffer;
+    vector<dcomplex>        itsShiftBuffer, itsSpectrumBuffer;
+};
+
+// @}
+
+} //# namespace DPPP
+} //# namespace LOFAR
+
+#endif
diff --git a/CEP/DP3/DPPP/src/Apply.cc b/CEP/DP3/DPPP/src/Apply.cc
index 761845bd196..cd5dadbfa8a 100644
--- a/CEP/DP3/DPPP/src/Apply.cc
+++ b/CEP/DP3/DPPP/src/Apply.cc
@@ -31,11 +31,6 @@ namespace DPPP
 void apply(size_t nBaseline, size_t nChannel, const_cursor<Baseline> baselines,
     const_cursor<double> coeff, cursor<dcomplex> data)
 {
-    dcomplex Jp_00, Jp_01, Jp_10, Jp_11;
-    dcomplex Jq_00, Jq_01, Jq_10, Jq_11;
-    dcomplex Jq_00_s0, Jq_10_s0, Jq_01_s1, Jq_11_s1, Jq_00_s2, Jq_10_s2,
-        Jq_01_s3, Jq_11_s3;
-
     for(size_t bl = 0; bl < nBaseline; ++bl)
     {
         const size_t p = baselines->first;
@@ -43,62 +38,56 @@ void apply(size_t nBaseline, size_t nChannel, const_cursor<Baseline> baselines,
 
         if(p != q)
         {
+            // Jones matrix for station P.
             coeff.forward(1, p);
-            Jp_00 = dcomplex(coeff[0], coeff[1]);
-            Jp_01 = dcomplex(coeff[2], coeff[3]);
-            Jp_10 = dcomplex(coeff[4], coeff[5]);
-            Jp_11 = dcomplex(coeff[6], coeff[7]);
+            const dcomplex Jp_00(coeff[0], coeff[1]);
+            const dcomplex Jp_01(coeff[2], coeff[3]);
+            const dcomplex Jp_10(coeff[4], coeff[5]);
+            const dcomplex Jp_11(coeff[6], coeff[7]);
             coeff.backward(1, p);
 
+            // Jones matrix for station Q, conjugated.
             coeff.forward(1, q);
-            Jq_00 = dcomplex(coeff[0], -coeff[1]);
-            Jq_01 = dcomplex(coeff[2], -coeff[3]);
-            Jq_10 = dcomplex(coeff[4], -coeff[5]);
-            Jq_11 = dcomplex(coeff[6], -coeff[7]);
+            const dcomplex Jq_00(coeff[0], -coeff[1]);
+            const dcomplex Jq_01(coeff[2], -coeff[3]);
+            const dcomplex Jq_10(coeff[4], -coeff[5]);
+            const dcomplex Jq_11(coeff[6], -coeff[7]);
             coeff.backward(1, q);
 
+            // Compute (Jp x conj(Jq)) * vec(data), where 'x' denotes the
+            // Kronecker product.
             for(size_t ch = 0; ch < nChannel; ++ch)
             {
-                Jq_00_s0 = Jq_00 * (*data);
-                Jq_10_s0 = Jq_10 * (*data);
-                ++data;
-
-                Jq_01_s1 = Jq_01 * (*data);
-                Jq_11_s1 = Jq_11 * (*data);
-                ++data;
-
-                Jq_00_s2 = Jq_00 * (*data);
-                Jq_10_s2 = Jq_10 * (*data);
-                ++data;
-
-                Jq_01_s3 = Jq_01 * (*data);
-                Jq_11_s3 = Jq_11 * (*data);
-                ++data;
-                data -= 4;
-
-                *data = Jp_00 * (Jq_00_s0 + Jq_01_s1)
-                    + Jp_01 * (Jq_00_s2 + Jq_01_s3);
-                ++data;
-
-                *data = Jp_00 * (Jq_10_s0 + Jq_11_s1)
-                    + Jp_01 * (Jq_10_s2 + Jq_11_s3);
-                ++data;
-
-                *data = Jp_10 * (Jq_00_s0 + Jq_01_s1)
-                    + Jp_11 * (Jq_00_s2 + Jq_01_s3);
-                ++data;
-
-                *data = Jp_10 * (Jq_10_s0 + Jq_11_s1)
-                    + Jp_11 * (Jq_10_s2 + Jq_11_s3);
-                ++data;
-                data -= 4;
-
-                // Move to next channel.
+                // Fetch visibilities.
+                const dcomplex xx = data[0];
+                const dcomplex xy = data[1];
+                const dcomplex yx = data[2];
+                const dcomplex yy = data[3];
+
+                // Precompute terms involving conj(Jq) and data. Each term
+                // appears twice in the computation of (Jp x conj(Jq))
+                // * vec(data).
+                const dcomplex Jq_00xx_01xy = Jq_00 * xx + Jq_01 * xy;
+                const dcomplex Jq_00yx_01yy = Jq_00 * yx + Jq_01 * yy;
+                const dcomplex Jq_10xx_11xy = Jq_10 * xx + Jq_11 * xy;
+                const dcomplex Jq_10yx_11yy = Jq_10 * yx + Jq_11 * yy;
+
+                // Compute (Jp x conj(Jq)) * vec(data) from the precomputed
+                // terms.
+                data[0] = Jp_00 * Jq_00xx_01xy + Jp_01 * Jq_00yx_01yy;
+                data[1] = Jp_00 * Jq_10xx_11xy + Jp_01 * Jq_10yx_11yy;
+                data[2] = Jp_10 * Jq_00xx_01xy + Jp_11 * Jq_00yx_01yy;
+                data[3] = Jp_10 * Jq_10xx_11xy + Jp_11 * Jq_10yx_11yy;
+
+                // Move to the next channel.
                 data.forward(1);
             } // Channels.
+
+            // Reset cursor to the beginning of the current baseline.
             data.backward(1, nChannel);
         }
 
+        // Move to the next baseline.
         data.forward(2);
         ++baselines;
     } // Baselines.
diff --git a/CEP/DP3/DPPP/src/BBSExpr.cc b/CEP/DP3/DPPP/src/BBSExpr.cc
deleted file mode 100644
index 02ff982bd9e..00000000000
--- a/CEP/DP3/DPPP/src/BBSExpr.cc
+++ /dev/null
@@ -1,221 +0,0 @@
-//# BBSExpr.cc: Create the expression tree for BBS
-//#
-//# Copyright (C) 2012
-//# 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$
-
-#include <lofar_config.h>
-#include <DPPP/BBSExpr.h>
-#include <DPPP/EstimateNDPPP.h>
-
-#include <BBSKernel/MeasurementAIPS.h>
-
-#include <Common/LofarLogger.h>
-#include <Common/lofar_iostream.h>
-#include <Common/lofar_iomanip.h>
-#include <Common/StreamUtil.h>
-
-#include <measures/Measures/MCDirection.h>
-#include <measures/Measures/MCPosition.h>
-#include <measures/Measures/MeasConvert.h>
-
-using namespace casa;
-using namespace LOFAR::BBS;
-
-namespace LOFAR {
-  namespace DPPP {
-
-    BBSExpr::BBSExpr (const DPInfo& info, const string& skyName,
-                      const string& instrumentName, double elevationCutoff)
-      : itsBaselineMask    (true),
-        itsCorrelationMask (true),
-        itsElevationCutoff (elevationCutoff)
-    {
-      // Open the sky SourceDB/ParmDB.
-      try {
-        itsSourceDB = boost::shared_ptr<SourceDB>
-          (new SourceDB(ParmDBMeta("casa", skyName)));
-        ParmManager::instance().initCategory(SKY, itsSourceDB->getParmDB());
-      } catch (Exception& e) {
-        THROW(Exception, "Failed to open sky model parameter database: "
-              << skyName);
-      }
-      // Open the instrument ParmDB.
-      try {
-        ParmManager::instance().initCategory
-          (INSTRUMENT, ParmDB(ParmDBMeta("casa", instrumentName)));
-      } catch (Exception& e) {
-        THROW(Exception, "Failed to open instrument model parameter database: "
-              << instrumentName);
-      }
-      // Create Instrument instance using the information present in DPInfo.
-      initInstrument(info);
-      // Store reference directions.
-      MDirection itsDelayRef = MDirection::Convert(info.delayCenter(),
-                                                   MDirection::J2000)();
-      MDirection itsTileRef  = MDirection::Convert(info.tileBeamDir(),
-                                                   MDirection::J2000)();
-
-      // Ignore auto-correlations.
-      ASSERT(info.getAnt1().size() == info.getAnt2().size());
-      for (size_t i=0; i<info.getAnt1().size(); ++i) {
-        int ant1 = info.getAnt1()[i];
-        int ant2 = info.getAnt2()[i];
-        itsBaselines.append(baseline_t(ant1, ant2));
-        if (ant1 == ant2) {
-          itsBaselineMask.clear (ant1, ant2);
-        }
-      }
-
-      // Use all correlations.
-      ASSERT(info.ncorr() == 4);
-      itsCorrelations.append(Correlation::XX);
-      itsCorrelations.append(Correlation::XY);
-      itsCorrelations.append(Correlation::YX);
-      itsCorrelations.append(Correlation::YY);
-    }
-
-    BBSExpr::~BBSExpr()
-    {}
-
-    void BBSExpr::setOptions (const SolverOptions& lsqOptions)
-    {
-      // Initialize parameter estimation options.
-      itsOptions = EstimateOptions(EstimateOptions::COMPLEX,
-                                   EstimateOptions::L2,
-                                   false,
-                                   0,
-                                   false,
-                                   ~flag_t(0),
-                                   flag_t(4),
-                                   lsqOptions);
-    }
-
-    void BBSExpr::addModel (const string& source, const MDirection& phaseRef)
-    {
-      // NB: The phase reference needs to be taken from the DPInfo object,
-      // because it is not necessarily equal to the phase center of the
-      // observation: A PhaseShift step may have shifted the phase center
-      // somewhere else.
-      MDirection phaseRefJ2000 = MDirection::Convert(phaseRef,
-                                                     MDirection::J2000)();
-      // Define the model configuration.
-      ModelConfig config;
-      config.setSources (vector<string>(1, source));
-      config.setDirectionalGain();
-      config.setCache();
-      if (itsElevationCutoff > 0) {
-        config.setElevationCutConfig (ElevationCutConfig(itsElevationCutoff));
-      }
-      // TODO: Find a better way to handle the reference frequency. Here we
-      // use a bogus reference frequency, which does not matter since we are
-      // not using the beam model. But it's still a hack, of course.
-      const double refFreq = 60.0e6;
-
-      // Create the model expression.
-      itsModels.push_back (MeasurementExpr::Ptr
-        (new MeasurementExprLOFAR (*itsSourceDB, BufferMap(), config,
-                                   itsInstrument, itsBaselines, refFreq,
-                                   phaseRefJ2000, itsDelayRef, itsTileRef)));
-
-      // Determine parameters to estimate and store for later reference.
-      vector<string> incl(1, "DirectionalGain:*"), excl;
-      ParmGroup parms = ParmManager::instance().makeSubset
-        (incl, excl, itsModels.back()->parms());
-      itsModelParms.push_back(parms);
-
-      // Update list of unique parameters to estimate (models can in principle
-      // share parameters).
-      itsParms.insert(parms.begin(), parms.end());
-    }
-
-    void BBSExpr::estimate (vector<vector<DPBuffer> >& buffers,
-                            const Grid& visGrid, const Grid& solveGrid,
-                            const vector<Array<DComplex> >& factors)
-    {
-      // Set parameter domain.
-      ParmManager::instance().setDomain(solveGrid.getBoundingBox());
-
-      // Force computation of partial derivatives of the model with respect to
-      // the parameters of interest.
-      setSolvables();
-
-      // Estimate parameter values.
-      DPPP::estimate (buffers, itsModels, factors, itsBaselines,
-                      itsCorrelations, itsBaselineMask, itsCorrelationMask,
-                      visGrid, solveGrid, itsOptions);
-
-      // Flush solutions to disk.
-      ParmManager::instance().flush();
-    }
-
-    void BBSExpr::subtract (vector<DPBuffer>& buffer,
-                            const Grid& visGrid,
-                            const vector<Array<DComplex> >& factors,
-                            uint target,
-                            uint nSources)
-    {
-      // Ensure computation of partial derivatives is switched off.
-      clearSolvables();
-
-      // Subtract selected sources from the data.
-      LOG_DEBUG_STR("nSources: " << nSources << ",  target: " << target);
-      DPPP::subtract (buffer, itsModels, factors, itsBaselines,
-                      itsCorrelations, itsBaselineMask, itsCorrelationMask,
-                      visGrid, target, nSources);
-    }
-
-    void BBSExpr::clearSolvables()
-    {
-      for (uint i=0; i<itsModels.size(); ++i) {
-        itsModels[i]->clearSolvables();
-      }
-    }
-
-    void BBSExpr::setSolvables()
-    {
-      for (uint i=0; i<itsModels.size(); ++i) {
-        itsModels[i]->setSolvables (itsModelParms[i]);
-      }
-    }
-
-    void BBSExpr::initInstrument(const DPInfo& info)
-    {
-      const size_t nStations = info.antennaNames().size();
-      vector<Station::Ptr> stations;
-      stations.reserve(nStations);
-      for (size_t i=0; i<nStations; ++i) {
-        // Get station name and ITRF position.
-        casa::MPosition position = MPosition::Convert(info.antennaPos()[i],
-                                                      MPosition::ITRF)();
-
-        // Store station information.
-        stations.push_back(Station::Ptr(new Station(info.antennaNames()(i),
-                                                    position)));
-      }
-
-      MPosition position = MPosition::Convert(info.arrayPos(),
-        MPosition::ITRF)();
-      itsInstrument = Instrument::Ptr(new Instrument("LOFAR", position,
-                                                     stations.begin(),
-                                                     stations.end()));
-    }
-
-  } //# namespace DPPP
-} //# namespace LOFAR
diff --git a/CEP/DP3/DPPP/src/CMakeLists.txt b/CEP/DP3/DPPP/src/CMakeLists.txt
index 2ab7135518e..9c3b4f87d6d 100644
--- a/CEP/DP3/DPPP/src/CMakeLists.txt
+++ b/CEP/DP3/DPPP/src/CMakeLists.txt
@@ -13,7 +13,7 @@ lofar_add_library(dppp
   StationAdder.cc Filter.cc
   PhaseShift.cc Demixer.cc
   Position.cc Stokes.cc SourceDBUtil.cc
-  Apply.cc EstimateMixed.cc Simulate.cc SubtractMixed.cc
+  Apply.cc EstimateMixed.cc Simulate.cc Simulator.cc SubtractMixed.cc
   ModelComponent.cc PointSource.cc GaussianSource.cc Patch.cc
   ModelComponentVisitor.cc
   FlaggerStatistics.cc
diff --git a/CEP/DP3/DPPP/src/Demixer.cc b/CEP/DP3/DPPP/src/Demixer.cc
index 74e542eede7..236f43c7f1f 100644
--- a/CEP/DP3/DPPP/src/Demixer.cc
+++ b/CEP/DP3/DPPP/src/Demixer.cc
@@ -35,8 +35,6 @@
 #include <DPPP/SourceDBUtil.h>
 #include <DPPP/SubtractMixed.h>
 
-#include <DPPP/PointSource.h>
-
 #include <ParmDB/Axis.h>
 #include <ParmDB/SourceDB.h>
 #include <ParmDB/ParmDB.h>
@@ -58,8 +56,6 @@
 #include <casa/Arrays/MatrixMath.h>
 #include <scimath/Mathematics/MatrixMathLA.h>
 
-#include <boost/multi_array.hpp>
-
 using namespace casa;
 
 namespace LOFAR {
@@ -67,44 +63,52 @@ namespace LOFAR {
 
     using LOFAR::operator<<;
 
-//    namespace {
-//      void pack(const vector<size_t> &directions, size_t nBl, size_t nCh,
-//        size_t nCr, const_cursor<dcomplex> in, cursor<dcomplex> out);
-//      void pack(const vector<size_t> &directions, size_t nStation,
-//        const_cursor<double> in, double *out);
-//      void unpack(const vector<size_t> &directions, size_t nStation,
-//        const double *in, cursor<double> out);
-//      Patch::Ptr makePatch(const string &name);
-//    } //# end unnamed namespace
+    namespace
+    {
+      string toString (double value);
+      double getAngle (const String& value);
+    } //# end unnamed namespace
 
     Demixer::Demixer (DPInput* input,
                       const ParSet& parset, const string& prefix)
-      : itsInput         (input),
-        itsName          (prefix),
-        itsSkyName       (parset.getString(prefix+"skymodel", "sky")),
-        itsInstrumentName(parset.getString(prefix+"instrumentmodel",
+      : itsInput          (input),
+        itsName           (prefix),
+        itsSkyName        (parset.getString(prefix+"skymodel", "sky")),
+        itsInstrumentName (parset.getString(prefix+"instrumentmodel",
                                            "instrument")),
-        itsTargetSource  (parset.getString(prefix+"targetsource", string())),
-        itsSubtrSources  (parset.getStringVector (prefix+"subtractsources")),
-        itsModelSources  (parset.getStringVector (prefix+"modelsources",
-                                                  vector<string>())),
-        itsExtraSources  (parset.getStringVector (prefix+"othersources",
-                                                  vector<string>())),
-//        itsCutOffs       (parset.getUintVector (prefix+"elevationcutoffs",
-//                                                  vector<uint>())),
-///        itsJointSolve    (parset.getBool  (prefix+"jointsolve", true)),
-        itsNTimeIn       (0),
-        itsNChanAvgSubtr (parset.getUint  (prefix+"freqstep", 1)),
-        itsNTimeAvgSubtr (parset.getUint  (prefix+"timestep", 1)),
-        itsNTimeOutSubtr (0),
-        itsNChanAvg      (parset.getUint  (prefix+"demixfreqstep",
-                                           itsNChanAvgSubtr)),
-        itsNTimeAvg      (parset.getUint  (prefix+"demixtimestep",
-                                           itsNTimeAvgSubtr)),
-        itsNTimeChunk    (parset.getUint  (prefix+"ntimechunk", 0)),
-        itsNTimeOut      (0),
-        itsNConverged    (0),
-        itsTimeCount     (0)
+        itsAvgResultSubtr (0),
+        itsTargetSource   (parset.getString(prefix+"targetsource", string())),
+        itsSubtrSources   (parset.getStringVector (prefix+"subtractsources")),
+        itsModelSources   (parset.getStringVector (prefix+"modelsources",
+                                                   vector<string>())),
+        itsExtraSources   (parset.getStringVector (prefix+"othersources",
+                                                   vector<string>())),
+//        itsCutOffs        (parset.getDoubleVector (prefix+"elevationcutoffs",
+//                                                   vector<double>())),
+//        itsJointSolve     (parset.getBool  (prefix+"jointsolve", true)),
+        itsNDir           (0),
+        itsNModel         (0),
+        itsNStation       (0),
+        itsNBl            (0),
+        itsNCorr          (0),
+        itsNChanIn        (0),
+        itsNTimeIn        (0),
+        itsNTimeDemix     (0),
+        itsNChanAvgSubtr  (parset.getUint  (prefix+"freqstep", 1)),
+        itsNTimeAvgSubtr  (parset.getUint  (prefix+"timestep", 1)),
+        itsNChanOutSubtr  (0),
+        itsNTimeOutSubtr  (0),
+        itsNTimeChunk     (parset.getUint  (prefix+"ntimechunk", 0)),
+        itsNTimeChunkSubtr(0),
+        itsNChanAvg       (parset.getUint  (prefix+"demixfreqstep",
+                                            itsNChanAvgSubtr)),
+        itsNTimeAvg       (parset.getUint  (prefix+"demixtimestep",
+                                            itsNTimeAvgSubtr)),
+        itsNChanOut       (0),
+        itsNTimeOut       (0),
+        itsTimeIntervalAvg(0),
+        itsTimeIndex      (0),
+        itsNConverged     (0)
     {
       // Get and set solver options.
 //      itsSolveOpt.maxIter =
@@ -122,18 +126,13 @@ namespace LOFAR {
 //      itsSolveOpt.useSVD  =
 //        parset.getBool  (prefix+"Solve.Options.UseSVD", true);
 
-      // Maybe optionally a parset parameter directions to give the
-      // directions of unknown sources.
-      // Or make sources a vector of vectors like [name, ra, dec] where
-      // ra and dec are optional.
-
       ASSERTSTR (!(itsSkyName.empty() || itsInstrumentName.empty()),
                  "An empty name is given for the sky and/or instrument model");
       // Default nr of time chunks is maximum number of threads.
       if (itsNTimeChunk == 0) {
         itsNTimeChunk = OpenMP::maxThreads();
       }
-      // Check that time windows fit nicely.
+      // Check that time windows fit integrally.
       ASSERTSTR ((itsNTimeChunk * itsNTimeAvg) % itsNTimeAvgSubtr == 0,
                  "time window should fit final averaging integrally");
       itsNTimeChunkSubtr = (itsNTimeChunk * itsNTimeAvg) / itsNTimeAvgSubtr;
@@ -224,56 +223,15 @@ namespace LOFAR {
       itsFirstSteps.push_back (targetAvgSubtr);
 
 //      while(itsCutOffs.size() < itsNModel) {
-//        itsCutOffs.push_back(0);
+//        itsCutOffs.push_back(0.0);
 //      }
 //      itsCutOffs.resize(itsNModel);
-
-//      itsFrames.reserve(OpenMP::maxThreads());
-//      itsConverters.reserve(OpenMP::maxThreads());
-//      for(size_t i = 0; i < OpenMP::maxThreads(); ++i) {
-//        MeasFrame frame;
-//        frame.set(input->arrayPos());
-//        frame.set(MEpoch());
-//        itsFrames.push_back(frame);
-
-//        // Using AZEL because AZELGEO produces weird results.
-//        itsConverters.push_back(MDirection::Convert(MDirection::Ref(MDirection::J2000),
-//          MDirection::Ref(MDirection::AZEL, itsFrames.back())));
-//      }
-    }
-
-    void Demixer::initUnknowns()
-    {
-      itsUnknowns.resize(IPosition(4, 8, itsNStation, itsNModel,
-        itsNTimeDemix));
-      itsUnknowns = 0.0;
-
-//      itsErrors.resize(IPosition(4, 8, itsNStation, itsNModel,
-//        itsNTimeDemix));
-//      itsErrors = 0.0;
-
-      itsLastKnowns.resize(IPosition(3, 8, itsNStation, itsNModel));
-      for(uint dr = 0; dr < itsNModel; ++dr) {
-        for(uint st = 0; st < itsNStation; ++st) {
-          itsLastKnowns(IPosition(3, 0, st, dr)) = 1.0;
-          itsLastKnowns(IPosition(3, 1, st, dr)) = 0.0;
-          itsLastKnowns(IPosition(3, 2, st, dr)) = 0.0;
-          itsLastKnowns(IPosition(3, 3, st, dr)) = 0.0;
-          itsLastKnowns(IPosition(3, 4, st, dr)) = 0.0;
-          itsLastKnowns(IPosition(3, 5, st, dr)) = 0.0;
-          itsLastKnowns(IPosition(3, 6, st, dr)) = 1.0;
-          itsLastKnowns(IPosition(3, 7, st, dr)) = 0.0;
-        }
-      }
-    }
-
-    Demixer::~Demixer()
-    {
     }
 
     void Demixer::updateInfo (const DPInfo& infoIn)
     {
       info() = infoIn;
+
       // Get size info.
       itsNStation = infoIn.antennaNames().size();
       itsNChanIn  = infoIn.nchan();
@@ -309,13 +267,13 @@ namespace LOFAR {
       itsNChanAvgSubtr = info().update (itsNChanAvgSubtr, itsNTimeAvgSubtr);
       itsNChanOutSubtr = info().nchan();
       ASSERTSTR (itsNChanAvg % itsNChanAvgSubtr == 0,
-		 "Demix averaging " << itsNChanAvg
-		 << " must be multiple of output averaging "
-		 << itsNChanAvgSubtr);
+        "Demix averaging " << itsNChanAvg
+        << " must be multiple of output averaging "
+        << itsNChanAvgSubtr);
       ASSERTSTR (itsNTimeAvg % itsNTimeAvgSubtr == 0,
-		 "Demix averaging " << itsNTimeAvg
-		 << " must be multiple of output averaging "
-		 << itsNTimeAvgSubtr);
+        "Demix averaging " << itsNTimeAvg
+        << " must be multiple of output averaging "
+        << itsNTimeAvgSubtr);
       // Store channel frequencies for the demix and subtract resolutions.
       itsFreqDemix = infoDemix.chanFreqs();
       itsFreqSubtr = getInfo().chanFreqs();
@@ -327,24 +285,40 @@ namespace LOFAR {
       itsPhaseRef = Position(angles.getBaseValue()[0],
                              angles.getBaseValue()[1]);
 
-      initUnknowns();
+      // Intialize the unknowns.
+      itsUnknowns.resize(itsNTimeDemix * itsNModel * itsNStation * 8);
+      itsLastKnowns.resize(itsNModel * itsNStation * 8);
+      vector<double>::iterator it = itsLastKnowns.begin();
+      vector<double>::iterator it_end = itsLastKnowns.end();
+      while(it != it_end)
+      {
+        *it++ = 1.0;
+        *it++ = 0.0;
+        *it++ = 0.0;
+        *it++ = 0.0;
+        *it++ = 0.0;
+        *it++ = 0.0;
+        *it++ = 1.0;
+        *it++ = 0.0;
+      }
     }
 
     void Demixer::show (std::ostream& os) const
     {
       os << "Demixer " << itsName << std::endl;
-      os << "  skymodel:       " << itsSkyName << std::endl;
-      os << "  instrumentmodel:" << itsInstrumentName << std::endl;
-      os << "  targetsource:   " << itsTargetSource << std::endl;
-      os << "  subtractsources:" << itsSubtrSources << std::endl;
-      os << "  modelsources:   " << itsModelSources << std::endl;
-      os << "  extrasources:   " << itsExtraSources << std::endl;
+      os << "  skymodel:         " << itsSkyName << std::endl;
+      os << "  instrumentmodel:  " << itsInstrumentName << std::endl;
+      os << "  targetsource:     " << itsTargetSource << std::endl;
+      os << "  subtractsources:  " << itsSubtrSources << std::endl;
+      os << "  modelsources:     " << itsModelSources << std::endl;
+      os << "  extrasources:     " << itsExtraSources << std::endl;
+//      os << "  elevationcutoffs: " << itsCutOffs << std::endl;
 //      os << "  jointsolve:     " << itsJointSolve << std::endl;
-      os << "  freqstep:       " << itsNChanAvgSubtr << std::endl;
-      os << "  timestep:       " << itsNTimeAvgSubtr << std::endl;
-      os << "  demixfreqstep:  " << itsNChanAvg << std::endl;
-      os << "  demixtimestep:  " << itsNTimeAvg << std::endl;
-      os << "  ntimechunk:     " << itsNTimeChunk << std::endl;
+      os << "  freqstep:         " << itsNChanAvgSubtr << std::endl;
+      os << "  timestep:         " << itsNTimeAvgSubtr << std::endl;
+      os << "  demixfreqstep:    " << itsNChanAvg << std::endl;
+      os << "  demixtimestep:    " << itsNTimeAvg << std::endl;
+      os << "  ntimechunk:       " << itsNTimeChunk << std::endl;
 //      os << "  Solve.Options.MaxIter:       " << itsSolveOpt.maxIter << endl;
 //      os << "  Solve.Options.EpsValue:      " << itsSolveOpt.epsValue << endl;
 //      os << "  Solve.Options.EpsDerivative: " << itsSolveOpt.epsDerivative << endl;
@@ -379,6 +353,9 @@ namespace LOFAR {
       os << "          ";
       FlagCounter::showPerc1 (os, itsTimerSolve.getElapsed(), self);
       os << " of it spent in estimating gains and computing residuals" << endl;
+      os << "          ";
+      FlagCounter::showPerc1 (os, itsTimerDump.getElapsed(), self);
+      os << " of it spent in writing gain solutions to disk" << endl;
     }
 
     bool Demixer::process (const DPBuffer& buf)
@@ -407,8 +384,7 @@ namespace LOFAR {
       }
       itsTimerPhaseShift.stop();
 
-      // For each itsNTimeAvg times, calculate the
-      // phase rotation per direction.
+      // For each itsNTimeAvg times, calculate the phase rotation per direction.
       itsTimerDemix.start();
       addFactors (newBuf, itsFactorBuf);
       if (itsNTimeIn % itsNTimeAvg == 0) {
@@ -418,29 +394,51 @@ namespace LOFAR {
                      itsNChanAvg);
         // Deproject sources without a model.
         deproject (itsFactors[itsNTimeOut], itsAvgResults, itsNTimeOut);
-        itsFactorBuf = Complex();   // clear summation buffer
+        itsFactorBuf = Complex();       // Clear summation buffer
         itsNTimeOut++;
       }
-      // Subtract is done with different averaging parameters, so
-      // calculate the factors for it.
+      // Subtract is done with different averaging parameters, so calculate the
+      // factors for it.
       addFactors (newBuf, itsFactorBufSubtr);
       if (itsNTimeIn % itsNTimeAvgSubtr == 0) {
         makeFactors (itsFactorBufSubtr, itsFactorsSubtr[itsNTimeOutSubtr],
                      itsAvgResultSubtr->get()[itsNTimeOutSubtr].getWeights(),
                      itsNChanOutSubtr,
                      itsNChanAvgSubtr);
-        itsFactorBufSubtr = Complex();   // clear summation buffer
+        itsFactorBufSubtr = Complex();  // Clear summation buffer
         itsNTimeOutSubtr++;
       }
       itsTimerDemix.stop();
 
-      // Do BBS solve, etc. when sufficient time slots have been collected.
+      // Estimate gains and subtract source contributions when sufficient time
+      // slots have been collected.
       if (itsNTimeOut == itsNTimeChunk) {
-        demix();
+        if(itsNModel > 0) {
+          itsTimerSolve.start();
+          demix();
+          itsTimerSolve.stop();
+        }
+
+        // Clear the input buffers.
+        for (size_t i=0; i<itsAvgResults.size(); ++i) {
+          itsAvgResults[i]->clear();
+        }
+
+        // Let the next step process the data.
+        for (uint i=0; i<itsNTimeOutSubtr; ++i) {
+          itsTimer.stop();
+          getNextStep()->process (itsAvgResultSubtr->get()[i]);
+          itsTimer.start();
+        }
+
+        // Clear the output buffer.
+        itsAvgResultSubtr->clear();
+
+        // Reset counters.
         itsNTimeIn       = 0;
         itsNTimeOut      = 0;
         itsNTimeOutSubtr = 0;
-        itsTimeCount += itsNTimeChunk;
+        itsTimeIndex += itsNTimeChunk;
       }
 
       itsTimer.stop();
@@ -449,10 +447,10 @@ namespace LOFAR {
 
     void Demixer::finish()
     {
+      itsTimer.start();
+
       // Process remaining entries.
       if (itsNTimeIn > 0) {
-        itsTimer.start();
-
         // Finish the initial steps (phaseshift and average).
         itsTimerPhaseShift.start();
         for (int i=0; i<int(itsFirstSteps.size()); ++i) {
@@ -481,13 +479,36 @@ namespace LOFAR {
         // Resize lists of mixing factors to the number of valid entries.
         itsFactors.resize(itsNTimeOut);
         itsFactorsSubtr.resize(itsNTimeOutSubtr);
+
         // Demix the source directions.
-        demix();
-        itsTimer.stop();
+        if(itsNModel > 0) {
+          itsTimerSolve.start();
+          demix();
+          itsTimerSolve.stop();
+        }
+
+        // Clear the input buffers.
+        for (size_t i=0; i<itsAvgResults.size(); ++i) {
+          itsAvgResults[i]->clear();
+        }
+
+        // Let the next step process the data.
+        for (uint i=0; i<itsNTimeOutSubtr; ++i) {
+          itsTimer.stop();
+          getNextStep()->process (itsAvgResultSubtr->get()[i]);
+          itsTimer.start();
+        }
+
+        // Clear the output buffer.
+        itsAvgResultSubtr->clear();
       }
 
       // Write solutions to disk in ParmDB format.
+      itsTimerDump.start();
       dumpSolutions();
+      itsTimerDump.stop();
+
+      itsTimer.stop();
 
       // Let the next steps finish.
       getNextStep()->finish();
@@ -702,356 +723,222 @@ namespace LOFAR {
       factors.reference (newFactors);
     }
 
+    namespace {
+      struct ThreadPrivateStorage
+      {
+        vector<double>    unknowns;
+        vector<double>    uvw;
+        vector<dcomplex>  model;
+        vector<dcomplex>  model_subtr;
+        size_t            count_converged;
+      };
+
+      void initThreadPrivateStorage(ThreadPrivateStorage &storage,
+        size_t nDirection, size_t nStation, size_t nBaseline, size_t nChannel,
+        size_t nChannelSubtr)
+      {
+        storage.unknowns.resize(nDirection * nStation * 8);
+        storage.uvw.resize(nStation * 3);
+        storage.model.resize(nDirection * nBaseline * nChannel * 4);
+        storage.model_subtr.resize(nBaseline * nChannelSubtr * 4);
+        storage.count_converged = 0;
+      }
+    } //# end unnamed namespace
+
     void Demixer::demix()
     {
-      // Only solve and subtract if multiple directions.
-      if (itsNDir > 1) {
-        // Collect buffers for each direction.
-        vector<vector<DPBuffer> > streams;
-        for (size_t i=0; i<itsAvgResults.size(); ++i) {
-          // Only the phased shifted and averaged data for directions which have
-          // an associated model should be used to estimate the directional
-          // response.
-          if(i < itsNModel) {
-            streams.push_back (itsAvgResults[i]->get());
-          }
-          // Clear the buffers.
-          itsAvgResults[i]->clear();
-        }
-
-        itsTimerSolve.start();
-
-        const size_t nTime = streams[0].size();
-        const size_t nThread = OpenMP::maxThreads();
-        const size_t nDr = itsNModel;
-        const size_t nSt = itsNStation;
-        const size_t nBl = itsBaselines.size();
-        const size_t nCh = itsFreqDemix.size();
-        const size_t nCr = 4;
-        const size_t timeFactor = itsNTimeAvg / itsNTimeAvgSubtr;
-        vector<DPBuffer> &target = itsAvgResultSubtr->get();
-
-//        // Thread-private index per direction of the last known "good" solution.
-//        boost::multi_array<int, 2> last(boost::extents[nDr][nThread]);
-//        fill(&(last[0][0]), &(last[0][0]) + nDr * nThread, -1);
-
-        // Thread-private buffer for the unknowns.
-        boost::multi_array<double, 2> unknowns(boost::extents[nThread]
-            [nDr * nSt * 8]);
-//        boost::multi_array<double, 2> errors(boost::extents[nThread]
-//            [nDr * nSt * 8]);
+      const size_t nThread = OpenMP::maxThreads();
+      const size_t nTime = itsAvgResults[0]->get().size();
+      const size_t nTimeSubtr = itsAvgResultSubtr->get().size();
+      const size_t multiplier = itsNTimeAvg / itsNTimeAvgSubtr;
+      const size_t nDr = itsNModel;
+      const size_t nDrSubtr = itsSubtrSources.size();
+      const size_t nSt = itsNStation;
+      const size_t nBl = itsBaselines.size();
+      const size_t nCh = itsFreqDemix.size();
+      const size_t nChSubtr = itsFreqSubtr.size();
+      const size_t nCr = 4;
+      const size_t nSamples = nBl * nCh * nCr;
+
+      vector<ThreadPrivateStorage> threadStorage(nThread);
+      for(vector<ThreadPrivateStorage>::iterator it = threadStorage.begin(),
+        end = threadStorage.end(); it != end; ++it)
+      {
+        initThreadPrivateStorage(*it, nDr, nSt, nBl, nCh, nChSubtr);
 
         // Copy solutions from global solution array to thread private solution
         // array (solution propagation between chunks).
-        for(size_t i = 0; i < nThread; ++i)
-        {
-            copy(&(itsLastKnowns(IPosition(3, 0, 0, 0))),
-                &(itsLastKnowns(IPosition(3, 0, 0, 0))) + nDr * nSt * 8,
-                &(unknowns[i][0]));
-        }
-
-        // Thread-private buffer for station UVW coordinates.
-        boost::multi_array<double, 3> uvw(boost::extents[nThread][nSt][3]);
-
-        // Thread-private buffer for the simulated visibilities for all
-        // directions at the demix resolution.
-        boost::multi_array<dcomplex, 5> buffer(boost::extents[nThread][nDr][nBl]
-            [nCh][nCr]);
-
-        // Thread-private buffer for the simulated visibilities for a single
-        // direction at the residual resolution.
-        const size_t nChRes = itsFreqSubtr.size();
-        boost::multi_array<dcomplex, 4> residual(boost::extents[nThread][nBl]
-            [nChRes][nCr]);
+        copy(itsLastKnowns.begin(), itsLastKnowns.end(), it->unknowns.begin());
+      }
 
-        // Thread-private convergence counter.
-        vector<size_t> converged(nThread, 0);
+      const_cursor<double> cr_freq = casa_const_cursor(itsFreqDemix);
+      const_cursor<double> cr_freqSubtr = casa_const_cursor(itsFreqSubtr);
+      const_cursor<Baseline> cr_baseline(&(itsBaselines[0]));
 
 #pragma omp parallel for
-        for(size_t i = 0; i < nTime; ++i)
+      for(size_t ts = 0; ts < nTime; ++ts)
+      {
+        const size_t thread = OpenMP::threadNum();
+        ThreadPrivateStorage &storage = threadStorage[thread];
+
+        // Simulate.
+        //
+        // Model visibilities for each direction of interest will be computed
+        // and stored.
+        size_t stride_uvw[2] = {1, 3};
+        cursor<double> cr_uvw_split(&(storage.uvw[0]), 2, stride_uvw);
+
+        size_t stride_model[3] = {1, nCr, nCr * nCh};
+        fill(storage.model.begin(), storage.model.end(), dcomplex());
+        for(size_t dr = 0; dr < nDr; ++dr)
         {
-            const size_t thread = OpenMP::threadNum();
-
-            // Compute elevations and determine which sources are visible.
-            // TODO: Investigate segfault in MeasRef...
-//            vector<size_t> drUp;
-//            Quantum<Double> qEpoch(streams[0][i].getTime(), "s");
-//            MEpoch mEpoch(qEpoch, MEpoch::UTC);
-//            itsFrames[thread].set(mEpoch);
-
-//            for(size_t dr = 0; dr < nDr; ++dr)
-//            {
-//                MVDirection drJ2000(itsPatchList[dr]->position()[0],
-//                    itsPatchList[dr]->position()[1]);
-//                MVDirection mvAzel(itsConverters[thread](drJ2000).getValue());
-//                Vector<Double> azel = mvAzel.getAngle("deg").getValue();
-
-//                if(azel(1) >= itsCutOffs[dr])
-//                {
-//                    drUp.push_back(dr);
-//                    last[dr][thread] = i;
-//                }
-//            }
-
-//            const size_t nDrUp = drUp.size();
-//            if(nDrUp == 0)
-//            {
-//                continue;
-//            }
-
-            // Simulate.
-            size_t strides[3] = {1, nCr, nCh * nCr};
-            size_t strides_split[2] = {1, 3};
-
-            const_cursor<Baseline> cr_baseline(&(itsBaselines[0]));
-            const_cursor<double> cr_freq(&(itsFreqDemix[0]));
-            const_cursor<double> cr_freqRes(&(itsFreqSubtr[0]));
-
-            cursor<double> cr_split(&(uvw[thread][0][0]), 2, strides_split);
-//            for(size_t dr = 0; dr < nDrUp; ++dr)
-            for(size_t dr = 0; dr < nDr; ++dr)
-            {
-                fill(&(buffer[thread][dr][0][0][0]),
-                    &(buffer[thread][dr][0][0][0]) + nBl * nCh * nCr,
-                    dcomplex(0.0, 0.0));
-
-//                const_cursor<double> cr_uvw =
-//                    casa_const_cursor(streams[drUp[dr]][i].getUVW());
-                const_cursor<double> cr_uvw =
-                    casa_const_cursor(streams[dr][i].getUVW());
-                splitUVW(nSt, nBl, cr_baseline, cr_uvw, cr_split);
-
-                cursor<dcomplex> cr_model(&(buffer[thread][dr][0][0][0]), 3,
-                    strides);
-//                simulate(itsPatchList[drUp[dr]]->position(),
-//                    itsPatchList[drUp[dr]], nSt, nBl, nCh, cr_baseline, cr_freq,
-//                    cr_split, cr_model);
-                simulate(itsPatchList[dr]->position(), itsPatchList[dr], nSt,
-                    nBl, nCh, cr_baseline, cr_freq, cr_split, cr_model);
-            }
-
-            // Estimate.
-//            vector<const_cursor<fcomplex> > cr_data(nDrUp);
-//            vector<const_cursor<dcomplex> > cr_model(nDrUp);
-            vector<const_cursor<fcomplex> > cr_data(nDr);
-            vector<const_cursor<dcomplex> > cr_model(nDr);
-//            for(size_t dr = 0; dr < nDrUp; ++dr)
-            for(size_t dr = 0; dr < nDr; ++dr)
-            {
-//                cr_data[dr] = casa_const_cursor(streams[drUp[dr]][i].getData());
-                cr_data[dr] = casa_const_cursor(streams[dr][i].getData());
-                cr_model[dr] =
-                    const_cursor<dcomplex>(&(buffer[thread][dr][0][0][0]), 3,
-                    strides);
-            }
-
-            const_cursor<bool> cr_flag =
-                casa_const_cursor(streams[0][i].getFlags());
-            const_cursor<float> cr_weight =
-                casa_const_cursor(streams[0][i].getWeights());
-
-            bool status = false;
-//            if(nDrUp != nDr)
-//            {
-//                vector<double> unknowns_packed(nDrUp * nSt * 8);
-//                vector<double> errors_packed(nDrUp * nSt * 8);
-//                vector<dcomplex> mix_packed(nDrUp * nDrUp * nCr * nCh * nBl);
-
-//                // pack unknowns, mixing factors
-//                size_t strides_mix[5] = {1, nDrUp, nDrUp * nDrUp, nCr * nDrUp
-//                  * nDrUp, nCh * nCr * nDrUp * nDrUp};
-//                pack(drUp, nBl, nCh, nCr, casa_const_cursor(itsFactors[i]),
-//                  cursor<dcomplex>(&(mix_packed[0]), 5, strides_mix));
-
-//                size_t strides_unknowns[3] = {1, 8, nSt * 8};
-//                pack(drUp, nSt, const_cursor<double>(&(unknowns[thread][0]), 3,
-//                  strides_unknowns), &(unknowns_packed[0]));
-
-//                const_cursor<dcomplex> cr_mix(&(mix_packed[0]), 5, strides_mix);
-
-//                // estimate
-//                status = estimate(nDrUp, nSt, nBl, nCh, cr_baseline, cr_data,
-//                    cr_model, cr_flag, cr_weight, cr_mix, &(unknowns_packed[0]),
-//                    &(errors_packed[0]));
-
-//                // unpack unknowns, errors
-//                unpack(drUp, nSt, &(unknowns_packed[0]),
-//                  cursor<double>(&(unknowns[thread][0]), 3, strides_unknowns));
-//                unpack(drUp, nSt, &(errors_packed[0]),
-//                  cursor<double>(&(errors[thread][0]), 3, strides_unknowns));
-//            }
-//            else
-            {
-                const_cursor<dcomplex> cr_mix =
-                    casa_const_cursor(itsFactors[i]);
-//                status = estimate(nDr, nSt, nBl, nCh, cr_baseline, cr_data,
-//                    cr_model, cr_flag, cr_weight, cr_mix,
-//                    &(unknowns[thread][0]), &(errors[thread][0]));
-                status = estimate(nDr, nSt, nBl, nCh, cr_baseline, cr_data,
-                    cr_model, cr_flag, cr_weight, cr_mix,
-                    &(unknowns[thread][0]), 0);
-            }
-
-            if(status)
-            {
-                ++converged[thread];
-            }
-
-            const size_t nTimeResidual = min(timeFactor, target.size() - i
-                * timeFactor);
-
-            const size_t nDrRes = itsSubtrSources.size();
-
-            size_t strides_model[3] = {1, nCr, nChRes * nCr};
-            cursor<dcomplex> cr_model_res(&(residual[thread][0][0][0]), 3,
-                strides_model);
+          const_cursor<double> cr_uvw =
+            casa_const_cursor(itsAvgResults[dr]->get()[ts].getUVW());
+          splitUVW(nSt, nBl, cr_baseline, cr_uvw, cr_uvw_split);
+
+          cursor<dcomplex> cr_model(&(storage.model[dr * nSamples]), 3,
+            stride_model);
+          simulate(itsPatchList[dr]->position(), itsPatchList[dr], nSt,
+            nBl, nCh, cr_baseline, cr_freq, cr_uvw_split, cr_model);
+        }
 
-            for(size_t j = 0; j < nTimeResidual; ++j)
-            {
-//                for(size_t dr = 0; dr < nDrUp; ++dr)
-                for(size_t dr = 0; dr < nDr; ++dr)
-                {
-//                    const size_t drIdx = drUp[dr];
-//                    if(drIdx >= nDrRes)
-                    if(dr >= nDrRes)
-                    {
-                        break;
-                    }
-
-                    // Re-simulate for residual if required.
-                    if(timeFactor != 1 || nCh != nChRes)
-                    {
-                        fill(&(residual[thread][0][0][0]),
-                            &(residual[thread][0][0][0]) + nBl * nChRes * nCr,
-                            dcomplex());
-
-                        const_cursor<double> cr_uvw = casa_const_cursor(target[i
-                            * timeFactor + j].getUVW());
-                        splitUVW(nSt, nBl, cr_baseline, cr_uvw, cr_split);
-
-//                        rotateUVW(itsPhaseRef, itsPatchList[drIdx]->position(),
-//                            nSt, cr_split);
-                        rotateUVW(itsPhaseRef, itsPatchList[dr]->position(),
-                            nSt, cr_split);
-
-//                        simulate(itsPatchList[drIdx]->position(),
-//                            itsPatchList[drIdx], nSt, nBl, nChRes, cr_baseline,
-//                            cr_freqRes, cr_split, cr_model_res);
-                        simulate(itsPatchList[dr]->position(), itsPatchList[dr],
-                            nSt, nBl, nChRes, cr_baseline, cr_freqRes, cr_split,
-                            cr_model_res);
-                    }
-                    else
-                    {
-                        copy(&(buffer[thread][dr][0][0][0]),
-                            &(buffer[thread][dr][0][0][0]) + nBl * nChRes * nCr,
-                            &(residual[thread][0][0][0]));
-                    }
-
-                    // Apply solutions.
-                    size_t strides_coeff[2] = {1, 8};
-//                    const_cursor<double> cr_coeff(&(unknowns[thread][drIdx * nSt
-//                        * 8]), 2, strides_coeff);
-                    const_cursor<double> cr_coeff(&(unknowns[thread][dr * nSt
-                        * 8]), 2, strides_coeff);
-                    apply(nBl, nChRes, cr_baseline, cr_coeff, cr_model_res);
-
-                    // Subtract.
-                    cursor<fcomplex> cr_residual =
-                        casa_cursor(target[i * timeFactor + j].getData());
-
-                    const IPosition tmp_strides_mix_res =
-                        itsFactorsSubtr[i * timeFactor + j].steps();
-
-                    // The target direction is always last, and therefore it has
-                    // index itsNDir - 1. The directions to subtract are always
-                    // first, and therefore have indices [0, nDrRes).
-//                    const_cursor<dcomplex> cr_mix(&(itsFactorsSubtr[i
-//                        * timeFactor + j](IPosition(5, itsNDir - 1, drIdx, 0, 0,
-//                        0))), 3, tmp_strides_mix_res.storage() + 2);
-                    const_cursor<dcomplex> cr_mix(&(itsFactorsSubtr[i
-                        * timeFactor + j](IPosition(5, itsNDir - 1, dr, 0, 0,
-                        0))), 3, tmp_strides_mix_res.storage() + 2);
-                    subtract(nBl, nChRes, cr_baseline, cr_residual,
-                        cr_model_res, cr_mix);
-                }
-            }
+        // Estimate Jones matrices.
+        //
+        // A Jones matrix will be estimated for each pair of station and
+        // direction.
+        //
+        // A single (overdetermined) non-linear set of equations for all
+        // stations and directions is solved iteratively. The influence of
+        // each direction on each other direction is given by the mixing
+        // matrix.
+        const_cursor<bool> cr_flag =
+          casa_const_cursor(itsAvgResults[0]->get()[ts].getFlags());
+        const_cursor<float> cr_weight =
+          casa_const_cursor(itsAvgResults[0]->get()[ts].getWeights());
+        const_cursor<dcomplex> cr_mix = casa_const_cursor(itsFactors[ts]);
+
+        vector<const_cursor<fcomplex> > cr_data(nDr);
+        vector<const_cursor<dcomplex> > cr_model(nDr);
+        for(size_t dr = 0; dr < nDr; ++dr)
+        {
+          cr_data[dr] =
+            casa_const_cursor(itsAvgResults[dr]->get()[ts].getData());
+          cr_model[dr] =
+            const_cursor<dcomplex>(&(storage.model[dr * nSamples]), 3,
+            stride_model);
+        }
 
-            // Copy solutions to global solution array.
-//            for(size_t dr = 0; dr < nDrUp; ++dr)
-            for(size_t dr = 0; dr < nDr; ++dr)
-            {
-//                size_t idx = drUp[dr];
-//                copy(&(unknowns[thread][idx * nSt * 8]), &(unknowns[thread][idx
-//                    * nSt * 8]) + nSt * 8, &(itsUnknowns(IPosition(4, 0, 0, idx,
-//                    itsTimeCount + i))));
-//                copy(&(errors[thread][idx * nSt * 8]), &(errors[thread][idx
-//                    * nSt * 8]) + nSt * 8, &(itsErrors(IPosition(4, 0, 0, idx,
-//                    itsTimeCount + i))));
-                copy(&(unknowns[thread][dr * nSt * 8]), &(unknowns[thread][dr
-                    * nSt * 8]) + nSt * 8, &(itsUnknowns(IPosition(4, 0, 0, dr,
-                    itsTimeCount + i))));
-            }
+        bool converged = estimate(nDr, nSt, nBl, nCh, cr_baseline, cr_data,
+          cr_model, cr_flag, cr_weight, cr_mix, &(storage.unknowns[0]));
+        if(converged)
+        {
+          ++storage.count_converged;
         }
 
-        // Store last known solutions.
-        for(size_t dr = 0; dr < nDr; ++dr)
+        // Compute the residual.
+        //
+        // All the so-called "subtract sources" are subtracted from the
+        // observed data. The previously estimated Jones matrices, as well as
+        // the appropriate mixing weight are applied before subtraction.
+        //
+        // Note that the resolution of the residual can differ from the
+        // resolution at which the Jones matrices were estimated.
+        for(size_t ts_subtr = multiplier * ts, ts_subtr_end = min(ts_subtr
+          + multiplier, nTimeSubtr); ts_subtr != ts_subtr_end; ++ts_subtr)
         {
-//            int idx = last[dr][0];
-//            for(size_t i = 1; i < nThread; ++i)
-//            {
-//                idx = max(idx, last[dr][i]);
-//            }
-            int idx = (nTime > 0 ? (nTime - 1) : -1);
-
-            if(idx >= 0)
+          for(size_t dr = 0; dr < nDrSubtr; ++dr)
+          {
+            // Re-use simulation used for estimating Jones matrices if possible.
+            cursor<dcomplex> cr_model_subtr(&(storage.model[dr * nSamples]),
+              3, stride_model);
+
+            // Re-simulate if required.
+            if(multiplier != 1 || nCh != nChSubtr)
             {
-                copy(&(itsUnknowns(IPosition(4, 0, 0, dr, itsTimeCount + idx))),
-                    &(itsUnknowns(IPosition(4, 0, 0, dr, itsTimeCount + idx)))
-                    + nSt * 8, &(itsLastKnowns(IPosition(3, 0, 0, dr))));
+              const_cursor<double> cr_uvw =
+                casa_const_cursor(itsAvgResultSubtr->get()[ts_subtr].getUVW());
+              splitUVW(nSt, nBl, cr_baseline, cr_uvw, cr_uvw_split);
+
+              // Rotate the UVW coordinates for the target direction to the
+              // direction of source to subtract. This is required because at
+              // the resolution of the residual the UVW coordinates for
+              // directions other than the target are unavailable (unless the
+              // resolution of the residual is equal to the resolution at which
+              // the Jones matrices were estimated, of course).
+              rotateUVW(itsPhaseRef, itsPatchList[dr]->position(), nSt,
+                cr_uvw_split);
+
+              // Zero the visibility buffer.
+              fill(storage.model_subtr.begin(), storage.model_subtr.end(),
+                dcomplex());
+
+              // Simulate visibilities at the resolution of the residual.
+              size_t stride_model_subtr[3] = {1, nCr, nCr * nChSubtr};
+              cr_model_subtr = cursor<dcomplex>(&(storage.model_subtr[0]), 3,
+                stride_model_subtr);
+              simulate(itsPatchList[dr]->position(), itsPatchList[dr], nSt, nBl,
+                nChSubtr, cr_baseline, cr_freqSubtr, cr_uvw_split,
+                cr_model_subtr);
             }
-        }
 
-        // Update convergence count.
-        for (size_t i=0; i<nThread; ++i) {
-          itsNConverged += converged[i];
+            // Apply Jones matrices.
+            size_t stride_unknowns[2] = {1, 8};
+            const_cursor<double> cr_unknowns(&(storage.unknowns[dr * nSt * 8]),
+              2, stride_unknowns);
+            apply(nBl, nChSubtr, cr_baseline, cr_unknowns, cr_model_subtr);
+
+            // Subtract the source contribution from the data.
+            cursor<fcomplex> cr_residual =
+              casa_cursor(itsAvgResultSubtr->get()[ts_subtr].getData());
+
+            // Construct a cursor to iterate over a slice of the mixing matrix
+            // at the resolution of the residual. The "to" and "from" direction
+            // are fixed. Since the full mixing matrix is 5-D, the slice is
+            // therefore 3-D. Each individual value in the slice quantifies the
+            // influence of the source to subtract on the target direction for
+            // a particular correlation, channel, and baseline.
+            //
+            // The target direction is the direction with the highest index by
+            // convention, i.e. index itsNDir - 1. The directions to subtract
+            // have the lowest indices by convention, i.e. indices
+            // [0, nDrSubtr).
+            const IPosition &stride_mix_subtr =
+              itsFactorsSubtr[ts_subtr].steps();
+            size_t stride_mix_subtr_slice[3] = {stride_mix_subtr[2],
+              stride_mix_subtr[3], stride_mix_subtr[4]};
+            ASSERT(stride_mix_subtr_slice[0] == itsNDir * itsNDir
+              && stride_mix_subtr_slice[1] == itsNDir * itsNDir * nCr
+              && stride_mix_subtr_slice[2] == itsNDir * itsNDir * nCr * nChSubtr);
+
+            IPosition offset(5, itsNDir - 1, dr, 0, 0, 0);
+            const_cursor<dcomplex> cr_mix_subtr =
+              const_cursor<dcomplex>(&(itsFactorsSubtr[ts_subtr](offset)), 3,
+              stride_mix_subtr_slice);
+
+            // Subtract the source.
+            subtract(nBl, nChSubtr, cr_baseline, cr_residual, cr_model_subtr,
+              cr_mix_subtr);
+          }
         }
 
-        itsTimerSolve.stop();
+        // Copy solutions to global solution array.
+        copy(storage.unknowns.begin(), storage.unknowns.end(),
+          &(itsUnknowns[(itsTimeIndex + ts) * nDr * nSt * 8]));
       }
 
-      // Let the next step process the data.
-      itsTimer.stop();
-      for (uint i=0; i<itsNTimeOutSubtr; ++i) {
-        getNextStep()->process (itsAvgResultSubtr->get()[i]);
-        itsAvgResultSubtr->get()[i].clear();
+      // Store last known solutions.
+      if(nTime > 0)
+      {
+        copy(&(itsUnknowns[(itsTimeIndex + nTime - 1) * nDr * nSt * 8]),
+          &(itsUnknowns[(itsTimeIndex + nTime) * nDr * nSt * 8]),
+          itsLastKnowns.begin());
       }
-      // Clear the vector in the MultiStep.
-      itsAvgResultSubtr->clear();
-      itsTimer.start();
-    }
-
-    string Demixer::toString (double value) const
-    {
-      ostringstream os;
-      os << setprecision(16) << value;
-      return os.str();
-    }
 
-    double Demixer::getAngle (const String& value) const
-    {
-      double angle;
-      Quantity q;
-      ASSERTSTR (Quantity::read (q, value),
-                 "Demixer: " + value + " is not a proper angle");
-      if (q.getUnit().empty()) {
-        angle = q.getValue() / 180. * C::pi;
-      } else {
-        ASSERTSTR (q.getFullUnit().getValue() == UnitVal::ANGLE,
-                   "Demixer: " + value + " is not a proper angle");
-        angle = q.getValue("rad");
+      // Update convergence count.
+      for(size_t i = 0; i < nThread; ++i)
+      {
+        itsNConverged += threadStorage[i].count_converged;
       }
-      return angle;
     }
 
     void Demixer::dumpSolutions()
@@ -1125,10 +1012,8 @@ namespace LOFAR {
 
       // Write solutions.
       for(size_t ts = 0; ts < itsNTimeDemix; ++ts) {
-        double *unknowns = &(itsUnknowns(IPosition(4, 0, 0, 0, ts)));
-//        double *errors = &(itsErrors(IPosition(4, 0, 0, 0, ts)));
+        double *unknowns = &(itsUnknowns[ts * itsNModel * itsNStation * 8]);
         for(size_t i = 0; i < parms.size(); ++i) {
-//          parms[i].setCoeff(BBS::Location(0, ts), unknowns + i, 1, errors + i);
           parms[i].setCoeff(BBS::Location(0, ts), unknowns + i, 1);
         }
       }
@@ -1137,6 +1022,31 @@ namespace LOFAR {
       parmCache.flush();
     }
 
+    namespace
+    {
+      string toString (double value)
+      {
+        ostringstream os;
+        os << setprecision(16) << value;
+        return os.str();
+      }
+
+      double getAngle (const String& value)
+      {
+        double angle;
+        Quantity q;
+        ASSERTSTR (Quantity::read (q, value),
+                   "Demixer: " + value + " is not a proper angle");
+        if (q.getUnit().empty()) {
+          angle = q.getValue() / 180. * C::pi;
+        } else {
+          ASSERTSTR (q.getFullUnit().getValue() == UnitVal::ANGLE,
+                     "Demixer: " + value + " is not a proper angle");
+          angle = q.getValue("rad");
+        }
+        return angle;
+      }
+    } //# end unnamed namespace
 
   } //# end namespace DPPP
 } //# end namespace LOFAR
diff --git a/CEP/DP3/DPPP/src/EstimateMixed.cc b/CEP/DP3/DPPP/src/EstimateMixed.cc
index 091d4773077..2cdbffa5af3 100644
--- a/CEP/DP3/DPPP/src/EstimateMixed.cc
+++ b/CEP/DP3/DPPP/src/EstimateMixed.cc
@@ -27,18 +27,50 @@
 #include <DPPP/EstimateMixed.h>
 #include <Common/LofarLogger.h>
 #include <scimath/Fitting/LSQFit.h>
-#include <boost/multi_array.hpp>
 
 namespace LOFAR
 {
 namespace DPPP
 {
 
+namespace
+{
+// Compute a map that contains the index of the unknowns related to the
+// specified baseline in the list of all unknowns.
+void makeIndex(size_t nDirection, size_t nStation, const Baseline &baseline,
+    unsigned int *index)
+{
+    const size_t nCorrelation = 4;
+    for(size_t cr = 0; cr < nCorrelation; ++cr)
+    {
+        size_t idx0 = baseline.first * 8 + (cr / 2) * 4;
+        size_t idx1 = baseline.second * 8 + (cr % 2) * 4;
+
+        for(size_t dr = 0; dr < nDirection; ++dr)
+        {
+            *index++ = idx0;
+            *index++ = idx0 + 1;
+            *index++ = idx0 + 2;
+            *index++ = idx0 + 3;
+
+            *index++ = idx1;
+            *index++ = idx1 + 1;
+            *index++ = idx1 + 2;
+            *index++ = idx1 + 3;
+
+            idx0 += nStation * 8;
+            idx1 += nStation * 8;
+        }
+    }
+}
+} // Unnamed namespace.
+
+
 bool estimate(size_t nDirection, size_t nStation, size_t nBaseline,
     size_t nChannel, const_cursor<Baseline> baselines,
     vector<const_cursor<fcomplex> > data, vector<const_cursor<dcomplex> > model,
     const_cursor<bool> flag, const_cursor<float> weight,
-    const_cursor<dcomplex> mix, double *unknowns, double *errors)
+    const_cursor<dcomplex> mix, double *unknowns)
 {
     ASSERT(data.size() == nDirection && model.size() == nDirection);
 
@@ -52,46 +84,13 @@ bool estimate(size_t nDirection, size_t nStation, size_t nBaseline,
     // each visibility provides information about (no. of directions) x 2 x 2
     // x 2 (scalar) unknowns = (no. of directions) x 8. For each of these
     // unknowns the value of the partial derivative of the model with respect
-    // to the unknow has to be computed.
-    const unsigned int nPartial = nDirection * 8;
-
-    // Construct partial derivative index template for each correlation.
-    boost::multi_array<unsigned int, 2> dIndexTemplate(boost::extents[4]
-        [nPartial]);
-    for(size_t cr = 0; cr < 4; ++cr)
-    {
-        size_t idx0 = (cr / 2) * 4;
-        size_t idx1 = (cr & 1) * 4;
-
-        for(size_t dr = 0; dr < nDirection; ++dr)
-        {
-            dIndexTemplate[cr][dr * 8 + 0] = idx0 + 0;
-            dIndexTemplate[cr][dr * 8 + 1] = idx0 + 1;
-            dIndexTemplate[cr][dr * 8 + 2] = idx0 + 2;
-            dIndexTemplate[cr][dr * 8 + 3] = idx0 + 3;
-            dIndexTemplate[cr][dr * 8 + 4] = idx1 + 0;
-            dIndexTemplate[cr][dr * 8 + 5] = idx1 + 1;
-            dIndexTemplate[cr][dr * 8 + 6] = idx1 + 2;
-            dIndexTemplate[cr][dr * 8 + 7] = idx1 + 3;
-            idx0 += nStation * 8;
-            idx1 += nStation * 8;
-        }
-    }
+    // to the unknown has to be computed.
+    const size_t nPartial = nDirection * 8;
+    vector<unsigned int> dIndex(4 * nPartial);
 
     // Allocate space for intermediate results.
-    boost::multi_array<dcomplex, 2> M(boost::extents[nDirection][4]);
-    boost::multi_array<dcomplex, 3> dM(boost::extents[nDirection][4][4]);
-    boost::multi_array<double, 1> dR(boost::extents[nPartial]);
-    boost::multi_array<double, 1> dI(boost::extents[nPartial]);
-    boost::multi_array<unsigned int, 2> dIndex(boost::extents[4][nPartial]);
-
-    dcomplex coherence;
-    dcomplex Jp_00, Jp_01, Jp_10, Jp_11;
-    dcomplex Jq_00, Jq_01, Jq_10, Jq_11;
-    dcomplex Jp_00_s0, Jp_10_s0, Jp_00_s1, Jp_10_s1, Jp_01_s2, Jp_11_s2,
-        Jp_01_s3, Jp_11_s3;
-    dcomplex Jq_00_s0, Jq_10_s0, Jq_01_s1, Jq_11_s1, Jq_00_s2, Jq_10_s2,
-        Jq_01_s3, Jq_11_s3;
+    vector<dcomplex> M(nDirection * 4), dM(nDirection * 16);
+    vector<double> dR(nPartial), dI(nPartial);
 
     // Iterate until convergence.
     size_t nIterations = 0;
@@ -104,103 +103,78 @@ bool estimate(size_t nDirection, size_t nStation, size_t nBaseline,
 
             if(p != q)
             {
-                // Update partial derivative index for current baseline.
-                const size_t offsetP = p * 8;
-                const size_t offsetQ = q * 8;
-                for(size_t cr = 0; cr < 4; ++cr)
-                {
-                    for(size_t dr = 0; dr < nDirection; ++dr)
-                    {
-                        dIndex[cr][dr * 8 + 0] = dIndexTemplate[cr][dr * 8 + 0]
-                            + offsetP;
-                        dIndex[cr][dr * 8 + 1] = dIndexTemplate[cr][dr * 8 + 1]
-                            + offsetP;
-                        dIndex[cr][dr * 8 + 2] = dIndexTemplate[cr][dr * 8 + 2]
-                            + offsetP;
-                        dIndex[cr][dr * 8 + 3] = dIndexTemplate[cr][dr * 8 + 3]
-                            + offsetP;
-
-                        dIndex[cr][dr * 8 + 4] = dIndexTemplate[cr][dr * 8 + 4]
-                            + offsetQ;
-                        dIndex[cr][dr * 8 + 5] = dIndexTemplate[cr][dr * 8 + 5]
-                            + offsetQ;
-                        dIndex[cr][dr * 8 + 6] = dIndexTemplate[cr][dr * 8 + 6]
-                            + offsetQ;
-                        dIndex[cr][dr * 8 + 7] = dIndexTemplate[cr][dr * 8 + 7]
-                            + offsetQ;
-                    }
-                }
+                // Create partial derivative index for current baseline.
+                makeIndex(nDirection, nStation, *baselines, &(dIndex[0]));
 
                 for(size_t ch = 0; ch < nChannel; ++ch)
                 {
-                    dcomplex coherence;
                     for(size_t dr = 0; dr < nDirection; ++dr)
                     {
+                        // Jones matrix for station P.
                         const double *Jp =
                             &(unknowns[dr * nStation * 8 + p * 8]);
-                        Jp_00 = dcomplex(Jp[0], Jp[1]);
-                        Jp_01 = dcomplex(Jp[2], Jp[3]);
-                        Jp_10 = dcomplex(Jp[4], Jp[5]);
-                        Jp_11 = dcomplex(Jp[6], Jp[7]);
+                        const dcomplex Jp_00(Jp[0], Jp[1]);
+                        const dcomplex Jp_01(Jp[2], Jp[3]);
+                        const dcomplex Jp_10(Jp[4], Jp[5]);
+                        const dcomplex Jp_11(Jp[6], Jp[7]);
 
+                        // Jones matrix for station Q, conjugated.
                         const double *Jq =
                             &(unknowns[dr * nStation * 8 + q * 8]);
-                        Jq_00 = dcomplex(Jq[0], -Jq[1]);
-                        Jq_01 = dcomplex(Jq[2], -Jq[3]);
-                        Jq_10 = dcomplex(Jq[4], -Jq[5]);
-                        Jq_11 = dcomplex(Jq[6], -Jq[7]);
-
-                        coherence = (model[dr][0]);
-                        Jp_00_s0 = Jp_00 * coherence;
-                        Jp_10_s0 = Jp_10 * coherence;
-                        Jq_00_s0 = Jq_00 * coherence;
-                        Jq_10_s0 = Jq_10 * coherence;
-
-                        coherence = (model[dr][1]);
-                        Jp_00_s1 = Jp_00 * coherence;
-                        Jp_10_s1 = Jp_10 * coherence;
-                        Jq_01_s1 = Jq_01 * coherence;
-                        Jq_11_s1 = Jq_11 * coherence;
-
-                        coherence = (model[dr][2]);
-                        Jp_01_s2 = Jp_01 * coherence;
-                        Jp_11_s2 = Jp_11 * coherence;
-                        Jq_00_s2 = Jq_00 * coherence;
-                        Jq_10_s2 = Jq_10 * coherence;
-
-                        coherence = (model[dr][3]);
-                        Jp_01_s3 = Jp_01 * coherence;
-                        Jp_11_s3 = Jp_11 * coherence;
-                        Jq_01_s3 = Jq_01 * coherence;
-                        Jq_11_s3 = Jq_11 * coherence;
-
-                        M[dr][0] = Jp_00 * (Jq_00_s0 + Jq_01_s1)
-                            + Jp_01 * (Jq_00_s2 + Jq_01_s3);
-                        dM[dr][0][0] = Jq_00_s0 + Jq_01_s1;
-                        dM[dr][0][1] = Jq_00_s2 + Jq_01_s3;
-                        dM[dr][0][2] = Jp_00_s0 + Jp_01_s2;
-                        dM[dr][0][3] = Jp_00_s1 + Jp_01_s3;
-
-                        M[dr][1] = Jp_00 * (Jq_10_s0 + Jq_11_s1)
-                            + Jp_01 * (Jq_10_s2 + Jq_11_s3);
-                        dM[dr][1][0] = Jq_10_s0 + Jq_11_s1;
-                        dM[dr][1][1] = Jq_10_s2 + Jq_11_s3;
-                        dM[dr][1][2] = dM[dr][0][2];
-                        dM[dr][1][3] = dM[dr][0][3];
-
-                        M[dr][2] = Jp_10 * (Jq_00_s0 + Jq_01_s1)
-                            + Jp_11 * (Jq_00_s2 + Jq_01_s3);
-                        dM[dr][2][0] = dM[dr][0][0];
-                        dM[dr][2][1] = dM[dr][0][1];
-                        dM[dr][2][2] = Jp_10_s0 + Jp_11_s2;
-                        dM[dr][2][3] = Jp_10_s1 + Jp_11_s3;
-
-                        M[dr][3] = Jp_10 * (Jq_10_s0 + Jq_11_s1)
-                            + Jp_11 * (Jq_10_s2 + Jq_11_s3);
-                        dM[dr][3][0] = dM[dr][1][0];
-                        dM[dr][3][1] = dM[dr][1][1];
-                        dM[dr][3][2] = dM[dr][2][2];
-                        dM[dr][3][3] = dM[dr][2][3];
+                        const dcomplex Jq_00(Jq[0], -Jq[1]);
+                        const dcomplex Jq_01(Jq[2], -Jq[3]);
+                        const dcomplex Jq_10(Jq[4], -Jq[5]);
+                        const dcomplex Jq_11(Jq[6], -Jq[7]);
+
+                        // Fetch model visibilities for the current direction.
+                        const dcomplex xx = model[dr][0];
+                        const dcomplex xy = model[dr][1];
+                        const dcomplex yx = model[dr][2];
+                        const dcomplex yy = model[dr][3];
+
+                        // Precompute terms involving conj(Jq) and the model
+                        // visibilities.
+                        const dcomplex Jq_00xx_01xy = Jq_00 * xx + Jq_01 * xy;
+                        const dcomplex Jq_00yx_01yy = Jq_00 * yx + Jq_01 * yy;
+                        const dcomplex Jq_10xx_11xy = Jq_10 * xx + Jq_11 * xy;
+                        const dcomplex Jq_10yx_11yy = Jq_10 * yx + Jq_11 * yy;
+
+                        // Precompute (Jp x conj(Jq)) * vec(data), where 'x'
+                        // denotes the Kronecker product. This is the model
+                        // visibility for the current direction, with the
+                        // current Jones matrix estimates applied. This is
+                        // stored in M.
+                        // Also, precompute the partial derivatives of M with
+                        // respect to all 16 parameters (i.e. 2 Jones matrices
+                        // Jp and Jq, 4 complex scalars per Jones matrix, 2 real
+                        // scalars per complex scalar, 2 * 4 * 2 = 16). These
+                        // partial derivatives are stored in dM.
+                        M[dr * 4] = Jp_00 * Jq_00xx_01xy + Jp_01 * Jq_00yx_01yy;
+                        dM[dr * 16] = Jq_00xx_01xy;
+                        dM[dr * 16 + 1] = Jq_00yx_01yy;
+                        dM[dr * 16 + 2] = Jp_00 * xx + Jp_01 * yx;
+                        dM[dr * 16 + 3] = Jp_00 * xy + Jp_01 * yy;
+
+                        M[dr * 4 + 1] = Jp_00 * Jq_10xx_11xy + Jp_01
+                            * Jq_10yx_11yy;
+                        dM[dr * 16 + 4] = Jq_10xx_11xy;
+                        dM[dr * 16 + 5] = Jq_10yx_11yy;
+                        dM[dr * 16 + 6] = dM[dr * 16 + 2];
+                        dM[dr * 16 + 7] = dM[dr * 16 + 3];
+
+                        M[dr * 4 + 2] = Jp_10 * Jq_00xx_01xy + Jp_11
+                            * Jq_00yx_01yy;
+                        dM[dr * 16 + 8] = dM[dr * 16];
+                        dM[dr * 16 + 9] = dM[dr * 16 + 1];
+                        dM[dr * 16 + 10] = Jp_10 * xx + Jp_11 * yx;
+                        dM[dr * 16 + 11] = Jp_10 * xy + Jp_11 * yy;
+
+                        M[dr * 4 + 3] = Jp_10 * Jq_10xx_11xy + Jp_11
+                            * Jq_10yx_11yy;
+                        dM[dr * 16 + 12] = dM[dr * 16 + 4];
+                        dM[dr * 16 + 13] = dM[dr * 16 + 5];
+                        dM[dr * 16 + 14] = dM[dr * 16 + 10];
+                        dM[dr * 16 + 15] = dM[dr * 16 + 11];
                     }
 
                     for(size_t cr = 0; cr < 4; ++cr)
@@ -209,39 +183,44 @@ bool estimate(size_t nDirection, size_t nStation, size_t nBaseline,
                         {
                             for(size_t tg = 0; tg < nDirection; ++tg)
                             {
-                                dcomplex model = 0.0, partial;
+                                dcomplex visibility(0.0, 0.0);
                                 for(size_t dr = 0; dr < nDirection; ++dr)
                                 {
-                                    // Look-up mixing term.
-                                    const dcomplex term = *mix;
-
-                                    // Update model visibility.
-                                    model += term * M[dr][cr];
-
-                                    // Compute partial derivatives.
-                                    partial = term * dM[dr][cr][0];
-                                    dR[dr * 8] = real(partial);
-                                    dI[dr * 8] = imag(partial);
-                                    dR[dr * 8 + 1] = -imag(partial);
-                                    dI[dr * 8 + 1] = real(partial);
-
-                                    partial = term * dM[dr][cr][1];
-                                    dR[dr * 8 + 2] = real(partial);
-                                    dI[dr * 8 + 2] = imag(partial);
-                                    dR[dr * 8 + 3] = -imag(partial);
-                                    dI[dr * 8 + 3] = real(partial);
-
-                                    partial = term * dM[dr][cr][2];
-                                    dR[dr * 8 + 4] = real(partial);
-                                    dI[dr * 8 + 4] = imag(partial);
-                                    dR[dr * 8 + 5] = imag(partial);
-                                    dI[dr * 8 + 5] = -real(partial);
-
-                                    partial = term * dM[dr][cr][3];
-                                    dR[dr * 8 + 6] = real(partial);
-                                    dI[dr * 8 + 6] = imag(partial);
-                                    dR[dr * 8 + 7] = imag(partial);
-                                    dI[dr * 8 + 7] = -real(partial);
+                                    // Look-up mixing weight.
+                                    const dcomplex mix_weight = *mix;
+
+                                    // Weight model visibility.
+                                    visibility += mix_weight * M[dr * 4 + cr];
+
+                                    // Compute weighted partial derivatives.
+                                    dcomplex derivative(0.0, 0.0);
+                                    derivative =
+                                        mix_weight * dM[dr * 16 + cr * 4];
+                                    dR[dr * 8] = real(derivative);
+                                    dI[dr * 8] = imag(derivative);
+                                    dR[dr * 8 + 1] = -imag(derivative);
+                                    dI[dr * 8 + 1] = real(derivative);
+
+                                    derivative =
+                                        mix_weight * dM[dr * 16 + cr * 4 + 1];
+                                    dR[dr * 8 + 2] = real(derivative);
+                                    dI[dr * 8 + 2] = imag(derivative);
+                                    dR[dr * 8 + 3] = -imag(derivative);
+                                    dI[dr * 8 + 3] = real(derivative);
+
+                                    derivative =
+                                        mix_weight * dM[dr * 16 + cr * 4 + 2];
+                                    dR[dr * 8 + 4] = real(derivative);
+                                    dI[dr * 8 + 4] = imag(derivative);
+                                    dR[dr * 8 + 5] = imag(derivative);
+                                    dI[dr * 8 + 5] = -real(derivative);
+
+                                    derivative =
+                                        mix_weight * dM[dr * 16 + cr * 4 + 3];
+                                    dR[dr * 8 + 6] = real(derivative);
+                                    dI[dr * 8 + 6] = imag(derivative);
+                                    dR[dr * 8 + 7] = imag(derivative);
+                                    dI[dr * 8 + 7] = -real(derivative);
 
                                     // Move to next source direction.
                                     mix.forward(1);
@@ -249,14 +228,17 @@ bool estimate(size_t nDirection, size_t nStation, size_t nBaseline,
 
                                 // Compute the residual.
                                 dcomplex residual =
-                                    static_cast<dcomplex>(data[tg][cr]) - model;
+                                  static_cast<dcomplex>(data[tg][cr])
+                                  - visibility;
 
                                 // Update the normal equations.
-                                solver.makeNorm(nPartial, &(dIndex[cr][0]),
-                                    &(dR[0]), static_cast<double>(weight[cr]),
+                                solver.makeNorm(nPartial,
+                                    &(dIndex[cr * nPartial]), &(dR[0]),
+                                    static_cast<double>(weight[cr]),
                                     real(residual));
-                                solver.makeNorm(nPartial, &(dIndex[cr][0]),
-                                    &(dI[0]), static_cast<double>(weight[cr]),
+                                solver.makeNorm(nPartial,
+                                    &(dIndex[cr * nPartial]), &(dI[0]),
+                                    static_cast<double>(weight[cr]),
                                     imag(residual));
 
                                 // Move to next target direction.
@@ -328,22 +310,6 @@ bool estimate(size_t nDirection, size_t nStation, size_t nBaseline,
         ++nIterations;
     }
 
-    // Get the estimated error for each unknown from the solver.
-    if(errors)
-    {
-//        boost::multi_array<double, 1> errors_packed(boost::extents[nUnknowns * nUnknowns]);
-//        // TODO: Somehow this only returns zero??
-//        bool status = solver.getErrors(&(errors_packed[0]));
-
-        vector<double> cov(nUnknowns * nUnknowns);
-        bool status = solver.getCovariance(&(cov[0]));
-        ASSERT(status);
-        for(size_t i = 0; i < nUnknowns; ++i)
-        {
-            errors[i] = sqrt(abs(cov[i * nUnknowns + i])) * solver.getSD();
-        }
-    }
-
     const bool converged = (solver.isReady() == casa::LSQFit::SOLINCREMENT
         || solver.isReady() == casa::LSQFit::DERIVLEVEL);
     return converged;
diff --git a/CEP/DP3/DPPP/src/Patch.cc b/CEP/DP3/DPPP/src/Patch.cc
index 6280d598bec..d75984adebb 100644
--- a/CEP/DP3/DPPP/src/Patch.cc
+++ b/CEP/DP3/DPPP/src/Patch.cc
@@ -30,15 +30,6 @@ namespace LOFAR
 namespace DPPP
 {
 
-void Patch::accept(ModelComponentVisitor &visitor) const
-{
-    for(const_iterator it = begin(), it_end = end(); it != it_end; ++it)
-    {
-        (*it)->accept(visitor);
-    }
-    visitor.visit(*this);
-}
-
 Patch::const_iterator Patch::begin() const
 {
     return itsComponents.begin();
@@ -53,27 +44,25 @@ void Patch::computePosition()
 {
     itsPosition = Position();
 
-    if(itsComponents.empty())
+    if(!itsComponents.empty())
     {
-        return;
-    }
+        double x = 0.0, y = 0.0, z = 0.0;
+        for(const_iterator it = begin(), it_end = end(); it != it_end; ++it)
+        {
+            const Position &position = (*it)->position();
+            double cosDec = cos(position[1]);
+            x += cos(position[0]) * cosDec;
+            y += sin(position[0]) * cosDec;
+            z += sin(position[1]);
+        }
 
-    double x = 0.0, y = 0.0, z = 0.0;
-    for(const_iterator it = begin(), it_end = end(); it != it_end; ++it)
-    {
-        const Position &position = (*it)->position();
-        double cosDec = cos(position[1]);
-        x += cos(position[0]) * cosDec;
-        y += sin(position[0]) * cosDec;
-        z += sin(position[1]);
-    }
+        x /= itsComponents.size();
+        y /= itsComponents.size();
+        z /= itsComponents.size();
 
-    x /= itsComponents.size();
-    y /= itsComponents.size();
-    z /= itsComponents.size();
-
-    itsPosition[0] = atan2(y, x);
-    itsPosition[1] = asin(z);
+        itsPosition[0] = atan2(y, x);
+        itsPosition[1] = asin(z);
+    }
 }
 
 } //# namespace DPPP
diff --git a/CEP/DP3/DPPP/src/PhaseShift.cc b/CEP/DP3/DPPP/src/PhaseShift.cc
index 70610f65e91..c2475222056 100644
--- a/CEP/DP3/DPPP/src/PhaseShift.cc
+++ b/CEP/DP3/DPPP/src/PhaseShift.cc
@@ -137,30 +137,30 @@ namespace LOFAR {
       //# to process.
 #pragma omp parallel for
       for (int i=0; i<nbl; ++i) {
-	Complex*  __restrict__ data    = newBuf.getData().data() + i*nchan*ncorr;
-	double*   __restrict__ uvw     = newBuf.getUVW().data() + i*3;
-	DComplex* __restrict__ phasors = itsPhasors.data() + i*nchan;
-	double u = uvw[0]*mat1[0] + uvw[1]*mat1[3] + uvw[2]*mat1[6];
-	double v = uvw[0]*mat1[1] + uvw[1]*mat1[4] + uvw[2]*mat1[7];
-	double w = uvw[0]*mat1[2] + uvw[1]*mat1[5] + uvw[2]*mat1[8];
-	double phase = itsXYZ[0]*uvw[0] + itsXYZ[1]*uvw[1] + itsXYZ[2]*uvw[2];
-	for (int j=0; j<nchan; ++j) {
-	  // Shift the phase of the data of this baseline.
-	  // Converting the phase term to wavelengths (and applying 2*pi)
-	  //      u_wvl = u_m / wvl = u_m * freq / c
-          // has been done once in the beginning (in updateInfo).
-	  double phasewvl = phase * itsFreqC[j];
-	  DComplex phasor(cos(phasewvl), sin(phasewvl));
-	  *phasors++ = phasor;
-	  for (int k=0; k<ncorr; ++k) {
-	    *data = DComplex(*data) * phasor;
-	    data++;
-	  }
-	}
-	uvw[0] = u;
-	uvw[1] = v;
-	uvw[2] = w;
-	uvw += 3;
+        Complex*  __restrict__ data    = newBuf.getData().data() + i*nchan*ncorr;
+        double*   __restrict__ uvw     = newBuf.getUVW().data() + i*3;
+        DComplex* __restrict__ phasors = itsPhasors.data() + i*nchan;
+        double u = uvw[0]*mat1[0] + uvw[1]*mat1[3] + uvw[2]*mat1[6];
+        double v = uvw[0]*mat1[1] + uvw[1]*mat1[4] + uvw[2]*mat1[7];
+        double w = uvw[0]*mat1[2] + uvw[1]*mat1[5] + uvw[2]*mat1[8];
+        double phase = itsXYZ[0]*uvw[0] + itsXYZ[1]*uvw[1] + itsXYZ[2]*uvw[2];
+        for (int j=0; j<nchan; ++j) {
+          // Shift the phase of the data of this baseline.
+          // Converting the phase term to wavelengths (and applying 2*pi)
+          //      u_wvl = u_m / wvl = u_m * freq / c
+                // has been done once in the beginning (in updateInfo).
+          double phasewvl = phase * itsFreqC[j];
+          DComplex phasor(cos(phasewvl), sin(phasewvl));
+          *phasors++ = phasor;
+          for (int k=0; k<ncorr; ++k) {
+            *data = DComplex(*data) * phasor;
+            data++;
+          }
+        }
+        uvw[0] = u;
+        uvw[1] = v;
+        uvw[2] = w;
+        uvw += 3;
       }  //# end omp parallel for
       itsTimer.stop();
       getNextStep()->process (newBuf);
diff --git a/CEP/DP3/DPPP/src/PointSource.cc b/CEP/DP3/DPPP/src/PointSource.cc
index 5e6468257fa..6cfb47dfdda 100644
--- a/CEP/DP3/DPPP/src/PointSource.cc
+++ b/CEP/DP3/DPPP/src/PointSource.cc
@@ -37,7 +37,8 @@ PointSource::PointSource(const Position &position)
         itsRefFreq(0.0),
         itsPolarizedFraction(0.0),
         itsPolarizationAngle(0.0),
-        itsRotationMeasure(0.0)
+        itsRotationMeasure(0.0),
+        itsHasRotationMeasure(false)
 {
 }
 
@@ -47,7 +48,8 @@ PointSource::PointSource(const Position &position, const Stokes &stokes)
         itsRefFreq(0.0),
         itsPolarizedFraction(0.0),
         itsPolarizationAngle(0.0),
-        itsRotationMeasure(0.0)
+        itsRotationMeasure(0.0),
+        itsHasRotationMeasure(false)
 {
 }
 
@@ -61,19 +63,12 @@ void PointSource::setStokes(const Stokes &stokes)
     itsStokes = stokes;
 }
 
-void PointSource::setPolarizedFraction(double fraction)
+void PointSource::setRotationMeasure(double fraction, double angle, double rm)
 {
     itsPolarizedFraction = fraction;
-}
-
-void PointSource::setPolarizationAngle(double angle)
-{
     itsPolarizationAngle = angle;
-}
-
-void PointSource::setRotationMeasure(double rm)
-{
     itsRotationMeasure = rm;
+    itsHasRotationMeasure = true;
 }
 
 Stokes PointSource::stokes(double freq) const
@@ -124,12 +119,12 @@ void PointSource::accept(ModelComponentVisitor &visitor) const
 
 bool PointSource::hasSpectralIndex() const
 {
-    return itsSpectralIndex.size() > 0;
+    return !itsSpectralIndex.empty();
 }
 
 bool PointSource::hasRotationMeasure() const
 {
-    return itsRotationMeasure > 0.0;
+    return itsHasRotationMeasure;
 }
 
 } //# namespace DPPP
diff --git a/CEP/DP3/DPPP/src/Simulate.cc b/CEP/DP3/DPPP/src/Simulate.cc
index 7b05559b346..200515705a5 100644
--- a/CEP/DP3/DPPP/src/Simulate.cc
+++ b/CEP/DP3/DPPP/src/Simulate.cc
@@ -22,12 +22,8 @@
 
 #include <lofar_config.h>
 #include <DPPP/Simulate.h>
-#include <DPPP/GaussianSource.h>
-#include <DPPP/ModelComponentVisitor.h>
-#include <DPPP/Patch.h>
-#include <DPPP/PointSource.h>
+#include <DPPP/Simulator.h>
 #include <Common/LofarLogger.h>
-#include <casa/BasicSL/Constants.h>
 
 // Only required for rotateUVW().
 #include <DPPP/PhaseShift.h>
@@ -39,78 +35,165 @@ namespace LOFAR
 namespace DPPP
 {
 
-namespace
-{
-// Compute LMN coordinates of \p position relative to \p reference.
-//
-// \param[in]   reference
-// Reference position on the celestial sphere.
-// \param[in]   position
-// Position of interest on the celestial sphere.
-// \param[in]   lmn
-// Pointer to a buffer of (at least) length three into which the computed LMN
-// coordinates will be written.
-void radec2lmn(const Position &reference, const Position &position,
-    cursor<double> lmn);
-
-void phases(size_t nStation, size_t nChannel, const_cursor<double> lmn,
-    const_cursor<double> uvw, const_cursor<double> freq,
-    cursor<dcomplex> shift);
-
-void spectrum(const PointSource &source, size_t nChannel,
-    const_cursor<double> freq, cursor<dcomplex> spectrum);
-} // Unnamed namespace.
-
 void splitUVW(size_t nStation, size_t nBaseline,
     const_cursor<Baseline> baselines, const_cursor<double> uvw,
     cursor<double> split)
 {
-    cursor<double> known(split);
-    vector<bool> flag(nStation, false);
-
-    split[0] = 0.0;
-    split[1] = 0.0;
-    split[2] = 0.0;
-    flag[0] = true;
-
+    // If the number of stations is zero, then the number of baselines should be
+    // zero as well because no valid baselines exist in this case.
+    ASSERT(nStation > 0 || nBaseline == 0);
+
+    // Flags to keep track of the stations for which the UVW coordinates are
+    // known.
+    vector<bool> flag(nStation, true);
+
+    // Find reachable stations, i.e. stations that participate in at least one
+    // (cross) baseline.
+    size_t nReachable = 0;
+    const_cursor<Baseline> tmp(baselines);
     for(size_t i = 0; i < nBaseline; ++i)
     {
-        const size_t p = baselines->first;
-        const size_t q = baselines->second;
-        if(p != q && flag[p] != flag[q])
+        const size_t p = tmp->first;
+        const size_t q = tmp->second;
+
+        if(p != q)
         {
             if(flag[p])
             {
-                known.forward(1, p);
-                split.forward(1, q);
-                split[0] = uvw[0] + known[0];
-                split[1] = uvw[1] + known[1];
-                split[2] = uvw[2] + known[2];
-                split.backward(1, q);
-                known.backward(1, p);
-                flag[q] = true;
+                flag[p] = false;
+                ++nReachable;
             }
-            else
+
+            if(flag[q])
             {
-                known.forward(1, q);
-                split.forward(1, p);
-                split[0] = -uvw[0] + known[0];
-                split[1] = -uvw[1] + known[1];
-                split[2] = -uvw[2] + known[2];
-                split.backward(1, p);
-                known.backward(1, q);
-                flag[p] = true;
+                flag[q] = false;
+                ++nReachable;
             }
         }
 
+        if(nReachable == nStation)
+        {
+            break;
+        }
+
         // Move to next baseline.
-        uvw.forward(1);
-        ++baselines;
-    } // Baselines.
+        ++tmp;
+    }
 
-    ASSERTSTR(static_cast<size_t>(std::count(flag.begin(), flag.end(), true))
-        == flag.size(), "Unable to split baseline UVW coordinates into station"
-        " UVW coordinates.");
+    // Zero the UVW coordinates of all unreachable stations and flag them as
+    // known.
+    if(nReachable < nStation)
+    {
+        for(size_t i = 0; i < nStation; ++i)
+        {
+            if(flag[i])
+            {
+                split.forward(1, i);
+                split[0] = 0.0;
+                split[1] = 0.0;
+                split[2] = 0.0;
+                split.backward(1, i);
+            }
+        }
+    }
+
+    // If no stations are reachable, nothing more can be done.
+    if(nReachable == 0)
+    {
+        return;
+    }
+
+    size_t ref = 0;
+    cursor<double> known(split);
+    while(true)
+    {
+        // Find first station for which UVW coordinates are unknown.
+        while(ref < nStation && flag[ref])
+        {
+            ++ref;
+        }
+
+        // UVW coordinates known for all stations, done.
+        if(ref == nStation)
+        {
+            break;
+        }
+
+        // Set UVW coordinates of the reference station to zero. Note that each
+        // isolated group of stations will have such a reference station. This
+        // is OK because the groups are isolated.
+        split.forward(1, ref);
+        split[0] = 0.0;
+        split[1] = 0.0;
+        split[2] = 0.0;
+        split.backward(1, ref);
+        flag[ref] = true;
+
+        // Single isolated station left, no use iterating over baselines.
+        if(ref == nStation - 1)
+        {
+            break;
+        }
+
+        bool done = false;
+        while(!done)
+        {
+            // Find UVW coordinates for other stations linked to the reference
+            // station via baselines.
+            size_t nFound = 0;
+            for(size_t i = 0; i < nBaseline; ++i)
+            {
+                const size_t p = baselines->first;
+                const size_t q = baselines->second;
+                if(p != q && flag[p] != flag[q])
+                {
+                    if(flag[p])
+                    {
+                        known.forward(1, p);
+                        split.forward(1, q);
+                        split[0] = uvw[0] + known[0];
+                        split[1] = uvw[1] + known[1];
+                        split[2] = uvw[2] + known[2];
+                        split.backward(1, q);
+                        known.backward(1, p);
+                        flag[q] = true;
+                    }
+                    else
+                    {
+                        known.forward(1, q);
+                        split.forward(1, p);
+                        split[0] = -uvw[0] + known[0];
+                        split[1] = -uvw[1] + known[1];
+                        split[2] = -uvw[2] + known[2];
+                        split.backward(1, p);
+                        known.backward(1, q);
+                        flag[p] = true;
+                    }
+
+                    ++nFound;
+                }
+
+                // Move to next baseline.
+                uvw.forward(1);
+                ++baselines;
+            } // Baselines.
+
+            // Reset cursors.
+            uvw.backward(1, nBaseline);
+            baselines -= nBaseline;
+
+            // Depending on the baseline order it may be possible to derive the
+            // UVW coordinates of additional stations when UVW coordinates were
+            // found for at leat one station (i.e. nFound larger than 0).
+            // Another iteration is required in this case, unless UVW
+            // coordinates were found for all (remaining) stations (i.e. nFound
+            // equals nStation - ref - 1).
+            done = (nFound == 0 || nFound == nStation - ref - 1);
+        }
+    }
+
+    ASSERT(static_cast<size_t>(std::count(flag.begin(), flag.end(), true))
+        == flag.size());
 }
 
 void rotateUVW(const Position &from, const Position &to, size_t nUVW,
@@ -140,282 +223,18 @@ void rotateUVW(const Position &from, const Position &to, size_t nUVW,
     } // Stations.
 }
 
-class SimulateVisitor: public ModelComponentVisitor
-{
-public:
-    SimulateVisitor(const Position &reference, size_t nStation,
-        size_t nBaseline, size_t nChannel, const_cursor<Baseline> baselines,
-        const_cursor<double> freq, const_cursor<double> uvw,
-        cursor<dcomplex> buffer)
-        :   itsReference(reference),
-            itsStationCount(nStation),
-            itsBaselineCount(nBaseline),
-            itsChannelCount(nChannel),
-            itsBaselines(baselines),
-            itsFreq(freq),
-            itsUVW(uvw),
-            itsBuffer(buffer),
-            itsShiftBuffer(nStation * nChannel),
-            itsSpectrumBuffer(nChannel * 4)
-    {
-    }
-
-    void simulate(const ModelComponent::ConstPtr &component)
-    {
-        component->accept(*this);
-    }
-
-private:
-    virtual void visit(const PointSource &source)
-    {
-        // Compute LMN coordinates.
-        double lmn[3];
-        radec2lmn(itsReference, source.position(), cursor<double>(lmn));
-
-        // Compute station phase shifts.
-        phases(itsStationCount, itsChannelCount, const_cursor<double>(lmn),
-            itsUVW, itsFreq, cursor<dcomplex>(&itsShiftBuffer[0]));
-
-        // Compute source spectrum.
-        spectrum(source, itsChannelCount, itsFreq,
-            cursor<dcomplex>(&itsSpectrumBuffer[0]));
-
-        // Compute visibilities.
-        for(size_t bl = 0; bl < itsBaselineCount; ++bl)
-        {
-            const size_t p = itsBaselines->first;
-            const size_t q = itsBaselines->second;
-
-            if(p != q)
-            {
-                const dcomplex *shiftP = &(itsShiftBuffer[p * itsChannelCount]);
-                const dcomplex *shiftQ = &(itsShiftBuffer[q * itsChannelCount]);
-                const dcomplex *spectrum = &(itsSpectrumBuffer[0]);
-                for(size_t ch = 0; ch < itsChannelCount; ++ch)
-                {
-                    // Compute baseline phase shift.
-                    const dcomplex blShift = (*shiftQ) * conj(*shiftP);
-                    ++shiftP;
-                    ++shiftQ;
-
-                    // Compute visibilities.
-                    *itsBuffer += blShift * (*spectrum);
-                    ++itsBuffer;
-                    ++spectrum;
-                    *itsBuffer += blShift * (*spectrum);
-                    ++itsBuffer;
-                    ++spectrum;
-                    *itsBuffer += blShift * (*spectrum);
-                    ++itsBuffer;
-                    ++spectrum;
-                    *itsBuffer += blShift * (*spectrum);
-                    ++itsBuffer;
-                    ++spectrum;
-
-                    // Move to next channel.
-                    itsBuffer -= 4;
-                    itsBuffer.forward(1);
-                } // Channels.
-
-                itsBuffer.backward(1, itsChannelCount);
-            }
-
-            // Move to next baseline.
-            itsBuffer.forward(2);
-            ++itsBaselines;
-        } // Baselines.
-
-        itsBuffer.backward(2, itsBaselineCount);
-        itsBaselines -= itsBaselineCount;
-    }
-
-    virtual void visit(const GaussianSource &source)
-    {
-        // Compute LMN coordinates.
-        double lmn[3];
-        radec2lmn(itsReference, source.position(), cursor<double>(lmn));
-
-        // Compute station phase shifts.
-        phases(itsStationCount, itsChannelCount, const_cursor<double>(lmn),
-            itsUVW, itsFreq, cursor<dcomplex>(&itsShiftBuffer[0]));
-
-        // Compute source spectrum.
-        spectrum(source, itsChannelCount, itsFreq,
-            cursor<dcomplex>(&itsSpectrumBuffer[0]));
-
-        // Convert position angle from North over East to the angle used to
-        // rotate the right-handed UV-plane.
-        // TODO: Can probably optimize by changing the rotation matrix instead.
-        const double phi = casa::C::pi_2 - source.positionAngle();
-        const double cosPhi = cos(phi);
-        const double sinPhi = sin(phi);
-
-        // Take care of the conversion of axis lengths from FWHM in radians to
-        // sigma.
-        // TODO: Shouldn't the projection from the celestial sphere to the
-        // UV-plane be taken into account here?
-        const double fwhm2sigma = 1.0 / (2.0 * std::sqrt(2.0 * std::log(2.0)));
-        const double uScale = source.majorAxis() * fwhm2sigma;
-        const double vScale = source.minorAxis() * fwhm2sigma;
-
-        for(size_t bl = 0; bl < itsBaselineCount; ++bl)
-        {
-            const size_t p = itsBaselines->first;
-            const size_t q = itsBaselines->second;
-
-            if(p != q)
-            {
-                itsUVW.forward(1, q);
-                double u = itsUVW[0];
-                double v = itsUVW[1];
-                itsUVW.backward(1, q);
-
-                itsUVW.forward(1, p);
-                u -= itsUVW[0];
-                v -= itsUVW[1];
-                itsUVW.backward(1, p);
-
-                // Rotate (u, v) by the position angle and scale with the major
-                // and minor axis lengths (FWHM in rad).
-                const double uPrime = uScale * (u * cosPhi - v * sinPhi);
-                const double vPrime = vScale * (u * sinPhi + v * cosPhi);
-
-                // Compute uPrime^2 + vPrime^2 and pre-multiply with -2.0 * PI^2
-                // / C^2.
-                const double uvPrime = (-2.0 * casa::C::pi * casa::C::pi)
-                    * (uPrime * uPrime + vPrime * vPrime);
-
-                const dcomplex *shiftP = &(itsShiftBuffer[p * itsChannelCount]);
-                const dcomplex *shiftQ = &(itsShiftBuffer[q * itsChannelCount]);
-                const dcomplex *spectrum = &(itsSpectrumBuffer[0]);
-
-                for(size_t ch = 0; ch < itsChannelCount; ++ch)
-                {
-                    // Compute baseline phase shift.
-                    dcomplex blShift = (*shiftQ) * conj(*shiftP);
-                    ++shiftP;
-                    ++shiftQ;
-
-                    const double ampl = exp(((*itsFreq) * (*itsFreq))
-                        / (casa::C::c * casa::C::c) * uvPrime);
-                    ++itsFreq;
-
-                    blShift *= ampl;
-
-                    // Compute visibilities.
-                    *itsBuffer += blShift * (*spectrum);
-                    ++itsBuffer;
-                    ++spectrum;
-                    *itsBuffer += blShift * (*spectrum);
-                    ++itsBuffer;
-                    ++spectrum;
-                    *itsBuffer += blShift * (*spectrum);
-                    ++itsBuffer;
-                    ++spectrum;
-                    *itsBuffer += blShift * (*spectrum);
-                    ++itsBuffer;
-                    ++spectrum;
-
-                    // Move to next channel.
-                    itsBuffer -= 4;
-                    itsBuffer.forward(1);
-                } // Channels.
-                itsFreq -= itsChannelCount;
-                itsBuffer.backward(1, itsChannelCount);
-            }
-
-            // Move to next baseline.
-            itsBuffer.forward(2);
-            ++itsBaselines;
-        } // Baselines.
-
-        itsBuffer.backward(2, itsBaselineCount);
-        itsBaselines -= itsBaselineCount;
-    }
-
-    virtual void visit(const Patch&)
-    {
-    }
-
-private:
-    Position                itsReference;
-    size_t                  itsStationCount;
-    size_t                  itsBaselineCount;
-    size_t                  itsChannelCount;
-    const_cursor<Baseline>  itsBaselines;
-    const_cursor<double>    itsFreq;
-    const_cursor<double>    itsUVW;
-    cursor<dcomplex>        itsBuffer;
-    vector<dcomplex>        itsShiftBuffer;
-    vector<dcomplex>        itsSpectrumBuffer;
-};
-
 void simulate(const Position &reference, const Patch::ConstPtr &patch,
     size_t nStation, size_t nBaseline, size_t nChannel,
     const_cursor<Baseline> baselines, const_cursor<double> freq,
     const_cursor<double> uvw, cursor<dcomplex> vis)
 {
-    SimulateVisitor visitor(reference, nStation, nBaseline, nChannel, baselines,
+    Simulator simulator(reference, nStation, nBaseline, nChannel, baselines,
         freq, uvw, vis);
-    visitor.simulate(patch);
-}
-
-namespace
-{
-inline void radec2lmn(const Position &reference, const Position &position,
-    cursor<double> lmn)
-{
-    const double dRA = position[0] - reference[0];
-    const double pDEC = position[1];
-    const double rDEC = reference[1];
-    const double cDEC = cos(pDEC);
-
-    const double l = cDEC * sin(dRA);
-    const double m = sin(pDEC) * cos(rDEC) - cDEC * sin(rDEC) * cos(dRA);
-
-    lmn[0] = l;
-    lmn[1] = m;
-    lmn[2] = sqrt(1.0 - l * l - m * m);
-}
-
-inline void phases(size_t nStation, size_t nChannel, const_cursor<double> lmn,
-    const_cursor<double> uvw, const_cursor<double> freq, cursor<dcomplex> shift)
-{
-    // Compute station phase shifts.
-    for(size_t st = 0; st < nStation; ++st)
+    for(size_t i = 0; i < patch->nComponents(); ++i)
     {
-        const double phase = casa::C::_2pi * (uvw[0] * lmn[0]
-            + uvw[1] * lmn[1] + uvw[2] * (lmn[2] - 1.0));
-        uvw.forward(1);
-
-        for(size_t ch = 0; ch < nChannel; ++ch)
-        {
-            const double chPhase = phase * (*freq) / casa::C::c;
-            *shift = dcomplex(cos(chPhase), sin(chPhase));
-            ++freq;
-            ++shift;
-        } // Channels.
-        freq -= nChannel;
-    } // Stations.
-}
-
-inline void spectrum(const PointSource &source, size_t nChannel,
-    const_cursor<double> freq, cursor<dcomplex> spectrum)
-{
-    // Compute source spectrum.
-    for(size_t ch = 0; ch < nChannel; ++ch)
-    {
-        Stokes stokes = source.stokes(*freq);
-        ++freq;
-
-        spectrum[0] = dcomplex(stokes.I + stokes.Q, 0.0);
-        spectrum[1] = dcomplex(stokes.U, stokes.V);
-        spectrum[2] = dcomplex(stokes.U, -stokes.V);
-        spectrum[3] = dcomplex(stokes.I - stokes.Q, 0.0);
-        spectrum += 4;
+      simulator.simulate(patch->component(i));
     }
 }
-} // Unnamed namespace.
 
 } //# namespace DPPP
 } //# namespace LOFAR
diff --git a/CEP/DP3/DPPP/src/Simulator.cc b/CEP/DP3/DPPP/src/Simulator.cc
new file mode 100644
index 00000000000..1e00ed20bca
--- /dev/null
+++ b/CEP/DP3/DPPP/src/Simulator.cc
@@ -0,0 +1,304 @@
+//# Simulator.cc: Compute visibilities for different model components types
+//# (implementation of ModelComponentVisitor).
+//#
+//# Copyright (C) 2012
+//# 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$
+
+#include <lofar_config.h>
+#include <DPPP/Simulator.h>
+#include <DPPP/GaussianSource.h>
+#include <DPPP/PointSource.h>
+#include <casa/BasicSL/Constants.h>
+
+namespace LOFAR
+{
+namespace DPPP
+{
+
+namespace
+{
+// Compute LMN coordinates of \p position relative to \p reference.
+//
+// \param[in]   reference
+// Reference position on the celestial sphere.
+// \param[in]   position
+// Position of interest on the celestial sphere.
+// \param[in]   lmn
+// Pointer to a buffer of (at least) length three into which the computed LMN
+// coordinates will be written.
+void radec2lmn(const Position &reference, const Position &position,
+    cursor<double> lmn);
+
+void phases(size_t nStation, size_t nChannel, const_cursor<double> lmn,
+    const_cursor<double> uvw, const_cursor<double> freq,
+    cursor<dcomplex> shift);
+
+void spectrum(const PointSource &component, size_t nChannel,
+    const_cursor<double> freq, cursor<dcomplex> spectrum);
+} // Unnamed namespace.
+
+Simulator::Simulator(const Position &reference, size_t nStation,
+    size_t nBaseline, size_t nChannel, const_cursor<Baseline> baselines,
+    const_cursor<double> freq, const_cursor<double> uvw,
+    cursor<dcomplex> buffer)
+    :   itsReference(reference),
+        itsNStation(nStation),
+        itsNBaseline(nBaseline),
+        itsNChannel(nChannel),
+        itsBaselines(baselines),
+        itsFreq(freq),
+        itsUVW(uvw),
+        itsBuffer(buffer),
+        itsShiftBuffer(nStation * nChannel),
+        itsSpectrumBuffer(nChannel * 4)
+{
+}
+
+void Simulator::simulate(const ModelComponent::ConstPtr &component)
+{
+    component->accept(*this);
+}
+
+void Simulator::visit(const PointSource &component)
+{
+    // Compute LMN coordinates.
+    double lmn[3];
+    radec2lmn(itsReference, component.position(), cursor<double>(lmn));
+
+    // Compute station phase shifts.
+    phases(itsNStation, itsNChannel, const_cursor<double>(lmn),
+        itsUVW, itsFreq, cursor<dcomplex>(&itsShiftBuffer[0]));
+
+    // Compute component spectrum.
+    spectrum(component, itsNChannel, itsFreq,
+        cursor<dcomplex>(&itsSpectrumBuffer[0]));
+
+    // Compute visibilities.
+    for(size_t bl = 0; bl < itsNBaseline; ++bl)
+    {
+        const size_t p = itsBaselines->first;
+        const size_t q = itsBaselines->second;
+
+        if(p != q)
+        {
+            const dcomplex *shiftP = &(itsShiftBuffer[p * itsNChannel]);
+            const dcomplex *shiftQ = &(itsShiftBuffer[q * itsNChannel]);
+            const dcomplex *spectrum = &(itsSpectrumBuffer[0]);
+            for(size_t ch = 0; ch < itsNChannel; ++ch)
+            {
+                // Compute baseline phase shift.
+                const dcomplex blShift = (*shiftQ) * conj(*shiftP);
+                ++shiftP;
+                ++shiftQ;
+
+                // Compute visibilities.
+                *itsBuffer += blShift * (*spectrum);
+                ++itsBuffer;
+                ++spectrum;
+                *itsBuffer += blShift * (*spectrum);
+                ++itsBuffer;
+                ++spectrum;
+                *itsBuffer += blShift * (*spectrum);
+                ++itsBuffer;
+                ++spectrum;
+                *itsBuffer += blShift * (*spectrum);
+                ++itsBuffer;
+                ++spectrum;
+
+                // Move to next channel.
+                itsBuffer -= 4;
+                itsBuffer.forward(1);
+            } // Channels.
+
+            itsBuffer.backward(1, itsNChannel);
+        }
+
+        // Move to next baseline.
+        itsBuffer.forward(2);
+        ++itsBaselines;
+    } // Baselines.
+
+    itsBuffer.backward(2, itsNBaseline);
+    itsBaselines -= itsNBaseline;
+}
+
+void Simulator::visit(const GaussianSource &component)
+{
+    // Compute LMN coordinates.
+    double lmn[3];
+    radec2lmn(itsReference, component.position(), cursor<double>(lmn));
+
+    // Compute station phase shifts.
+    phases(itsNStation, itsNChannel, const_cursor<double>(lmn),
+        itsUVW, itsFreq, cursor<dcomplex>(&itsShiftBuffer[0]));
+
+    // Compute component spectrum.
+    spectrum(component, itsNChannel, itsFreq,
+        cursor<dcomplex>(&itsSpectrumBuffer[0]));
+
+    // Convert position angle from North over East to the angle used to
+    // rotate the right-handed UV-plane.
+    // TODO: Can probably optimize by changing the rotation matrix instead.
+    const double phi = casa::C::pi_2 - component.positionAngle();
+    const double cosPhi = cos(phi);
+    const double sinPhi = sin(phi);
+
+    // Take care of the conversion of axis lengths from FWHM in radians to
+    // sigma.
+    // TODO: Shouldn't the projection from the celestial sphere to the
+    // UV-plane be taken into account here?
+    const double fwhm2sigma = 1.0 / (2.0 * std::sqrt(2.0 * std::log(2.0)));
+    const double uScale = component.majorAxis() * fwhm2sigma;
+    const double vScale = component.minorAxis() * fwhm2sigma;
+
+    for(size_t bl = 0; bl < itsNBaseline; ++bl)
+    {
+        const size_t p = itsBaselines->first;
+        const size_t q = itsBaselines->second;
+
+        if(p != q)
+        {
+            itsUVW.forward(1, q);
+            double u = itsUVW[0];
+            double v = itsUVW[1];
+            itsUVW.backward(1, q);
+
+            itsUVW.forward(1, p);
+            u -= itsUVW[0];
+            v -= itsUVW[1];
+            itsUVW.backward(1, p);
+
+            // Rotate (u, v) by the position angle and scale with the major
+            // and minor axis lengths (FWHM in rad).
+            const double uPrime = uScale * (u * cosPhi - v * sinPhi);
+            const double vPrime = vScale * (u * sinPhi + v * cosPhi);
+
+            // Compute uPrime^2 + vPrime^2 and pre-multiply with -2.0 * PI^2
+            // / C^2.
+            const double uvPrime = (-2.0 * casa::C::pi * casa::C::pi)
+                * (uPrime * uPrime + vPrime * vPrime);
+
+            const dcomplex *shiftP = &(itsShiftBuffer[p * itsNChannel]);
+            const dcomplex *shiftQ = &(itsShiftBuffer[q * itsNChannel]);
+            const dcomplex *spectrum = &(itsSpectrumBuffer[0]);
+
+            for(size_t ch = 0; ch < itsNChannel; ++ch)
+            {
+                // Compute baseline phase shift.
+                dcomplex blShift = (*shiftQ) * conj(*shiftP);
+                ++shiftP;
+                ++shiftQ;
+
+                const double ampl = exp(((*itsFreq) * (*itsFreq))
+                    / (casa::C::c * casa::C::c) * uvPrime);
+                ++itsFreq;
+
+                blShift *= ampl;
+
+                // Compute visibilities.
+                *itsBuffer += blShift * (*spectrum);
+                ++itsBuffer;
+                ++spectrum;
+                *itsBuffer += blShift * (*spectrum);
+                ++itsBuffer;
+                ++spectrum;
+                *itsBuffer += blShift * (*spectrum);
+                ++itsBuffer;
+                ++spectrum;
+                *itsBuffer += blShift * (*spectrum);
+                ++itsBuffer;
+                ++spectrum;
+
+                // Move to next channel.
+                itsBuffer -= 4;
+                itsBuffer.forward(1);
+            } // Channels.
+            itsFreq -= itsNChannel;
+            itsBuffer.backward(1, itsNChannel);
+        }
+
+        // Move to next baseline.
+        itsBuffer.forward(2);
+        ++itsBaselines;
+    } // Baselines.
+
+    itsBuffer.backward(2, itsNBaseline);
+    itsBaselines -= itsNBaseline;
+}
+
+namespace
+{
+inline void radec2lmn(const Position &reference, const Position &position,
+    cursor<double> lmn)
+{
+    const double dRA = position[0] - reference[0];
+    const double pDEC = position[1];
+    const double rDEC = reference[1];
+    const double cDEC = cos(pDEC);
+
+    const double l = cDEC * sin(dRA);
+    const double m = sin(pDEC) * cos(rDEC) - cDEC * sin(rDEC) * cos(dRA);
+
+    lmn[0] = l;
+    lmn[1] = m;
+    lmn[2] = sqrt(1.0 - l * l - m * m);
+}
+
+inline void phases(size_t nStation, size_t nChannel, const_cursor<double> lmn,
+    const_cursor<double> uvw, const_cursor<double> freq, cursor<dcomplex> shift)
+{
+    // Compute station phase shifts.
+    for(size_t st = 0; st < nStation; ++st)
+    {
+        const double phase = casa::C::_2pi * (uvw[0] * lmn[0]
+            + uvw[1] * lmn[1] + uvw[2] * (lmn[2] - 1.0));
+        uvw.forward(1);
+
+        for(size_t ch = 0; ch < nChannel; ++ch)
+        {
+            const double chPhase = phase * (*freq) / casa::C::c;
+            *shift = dcomplex(cos(chPhase), sin(chPhase));
+            ++freq;
+            ++shift;
+        } // Channels.
+        freq -= nChannel;
+    } // Stations.
+}
+
+inline void spectrum(const PointSource &component, size_t nChannel,
+    const_cursor<double> freq, cursor<dcomplex> spectrum)
+{
+    // Compute component spectrum.
+    for(size_t ch = 0; ch < nChannel; ++ch)
+    {
+        Stokes stokes = component.stokes(*freq);
+        ++freq;
+
+        spectrum[0] = dcomplex(stokes.I + stokes.Q, 0.0);
+        spectrum[1] = dcomplex(stokes.U, stokes.V);
+        spectrum[2] = dcomplex(stokes.U, -stokes.V);
+        spectrum[3] = dcomplex(stokes.I - stokes.Q, 0.0);
+        spectrum += 4;
+    }
+}
+} // Unnamed namespace.
+
+} //# namespace DPPP
+} //# namespace LOFAR
diff --git a/CEP/DP3/DPPP/src/SourceDBUtil.cc b/CEP/DP3/DPPP/src/SourceDBUtil.cc
index 9217ca7d773..3dcd5c6037a 100644
--- a/CEP/DP3/DPPP/src/SourceDBUtil.cc
+++ b/CEP/DP3/DPPP/src/SourceDBUtil.cc
@@ -110,9 +110,8 @@ vector<Patch::ConstPtr> makePatches(SourceDB &sourceDB,
         // Fetch rotation measure attributes (if applicable).
         if(src.getInfo().getUseRotationMeasure())
         {
-          source->setPolarizedFraction(src.getPolarizedFraction());
-          source->setPolarizationAngle(src.getPolarizationAngle());
-          source->setRotationMeasure(src.getRotationMeasure());
+          source->setRotationMeasure(src.getPolarizedFraction(),
+            src.getPolarizationAngle(), src.getRotationMeasure());
         }
 
         componentsList[i].push_back(source);
diff --git a/CEP/DP3/DPPP/src/SubtractMixed.cc b/CEP/DP3/DPPP/src/SubtractMixed.cc
index 54f24daa75f..3359f4d0723 100644
--- a/CEP/DP3/DPPP/src/SubtractMixed.cc
+++ b/CEP/DP3/DPPP/src/SubtractMixed.cc
@@ -42,7 +42,7 @@ void subtract(size_t nBaseline, size_t nChannel,
         {
             for(size_t ch = 0; ch < nChannel; ++ch)
             {
-                // Update visibilities.
+                // Subtract weighted model from data.
                 *data -= static_cast<fcomplex>((*weight) * (*model));
                 ++weight;
                 ++model;
@@ -60,7 +60,7 @@ void subtract(size_t nBaseline, size_t nChannel,
                 ++model;
                 ++data;
 
-                // Move to next channel.
+                // Move to the next channel.
                 weight -= 4;
                 weight.forward(1);
                 model -= 4;
@@ -74,6 +74,7 @@ void subtract(size_t nBaseline, size_t nChannel,
             data.backward(1, nChannel);
         }
 
+        // Move to the next baseline.
         weight.forward(2);
         model.forward(2);
         data.forward(2);
-- 
GitLab