diff --git a/CEP/BB/BBSControl/include/BBSControl/CommandExecutor.h b/CEP/BB/BBSControl/include/BBSControl/CommandExecutor.h
index 4c491bfe26b1cf759e404369bb876849db4dae1a..11775f9eaed6f88f00b706e32167f56e6e728355 100644
--- a/CEP/BB/BBSControl/include/BBSControl/CommandExecutor.h
+++ b/CEP/BB/BBSControl/include/BBSControl/CommandExecutor.h
@@ -78,14 +78,11 @@ namespace LOFAR
       // @}
 
       // Get result of the last executed command.
-      const CommandResult &getResult()
-      {
-          return itsResult;
-      }
+      const CommandResult &getResult() const
+      { return itsResult; }
 
-    private:
-      bool convertTime(string in, double &out);
 
+    private:
       // Kernel.
       scoped_ptr<Prediffer>                   itsKernel;
 
@@ -95,14 +92,6 @@ namespace LOFAR
       // Connection to the solver.
       shared_ptr<BlobStreamableConnection>    itsSolverConnection;
 
-      // Region of interest.
-      int32                                   itsROIFrequency[2];
-      double                                  itsROITime[2];
-
-      // Chunk size and position (in time).
-      double                                  itsChunkSize;
-      double                                  itsChunkPosition;
-
       // Result of the last executed command.
       CommandResult                           itsResult;
     };
diff --git a/CEP/BB/BBSControl/include/BBSControl/DomainRegistrationRequest.h b/CEP/BB/BBSControl/include/BBSControl/DomainRegistrationRequest.h
index ed69ff0972353d0ffc4cbf7c07dd7b9ac3389840..b6eb8770793bc920345b9717d4840ffdcb765d7c 100644
--- a/CEP/BB/BBSControl/include/BBSControl/DomainRegistrationRequest.h
+++ b/CEP/BB/BBSControl/include/BBSControl/DomainRegistrationRequest.h
@@ -25,7 +25,8 @@
 #define LOFAR_BBSCONTROL_DOMAINREGISTRATIONREQUEST_H
 
 // \file
-// Request sent from kernel to solver to register a solve domain and set the initial values of the unknowns.
+// Request sent from kernel to solver to register a solve domain and set the
+// initial values of the unknowns.
 
 
 #include <Blob/BlobStreamable.h>
@@ -34,63 +35,74 @@
 
 namespace LOFAR
 {
-    class BlobIStream;
-    class BlobOStream;
+class BlobIStream;
+class BlobOStream;
 
 namespace BBS
 {
     // \addtogroup BBSControl
     // @{
 
-    // Request sent from kernel to solver to register a solve domain and set the initial values of the
-    // unknowns.
+    // Request sent from kernel to solver to register a solve domain and set the
+    // initial values of the unknowns.
     //
-    // Note that the initial values are not necessary for computing a solution, because a single iteration consists
-    // of computing the solution to a set of linear (normal) equations (see AIPS++ note 224). However, they seem to
-    // be needed to check for convergence (inside LSQFit).
+    // Note that the initial values are not necessary for computing a solution,
+    // because a single iteration consists of computing the solution to a
+    // set of linear (normal) equations (see AIPS++ note 224). However, they
+    // seem to be needed to check for convergence (inside LSQFit).
     class DomainRegistrationRequest : public BlobStreamable
     {
     public:
         DomainRegistrationRequest(uint32 domainIndex = 0)
             :   itsDomainIndex(domainIndex),
+                itsMaxIter(0),
                 itsEpsilon(1e-8),
-                itsMaxIter(0)
+                itsColFactor(1e-8),
+                itsLMFactor(1.0),
+                itsBalancedEq(false)
         {
         }
-    
-        DomainRegistrationRequest(uint32 domainIndex, double epsilon, uint32 maxIter, const vector<double> &unknowns)
+
+        DomainRegistrationRequest(uint32 domainIndex,
+            const vector<double> &unknowns, uint32 maxIter = 0,
+            double epsilon = 1e-8, double colFactor = 1e-8,
+            double lmFactor = 1.0, bool balancedEq = false)
             :   itsDomainIndex(domainIndex),
-                itsEpsilon(epsilon),
                 itsMaxIter(maxIter),
+                itsEpsilon(epsilon),
+                itsColFactor(colFactor),
+                itsLMFactor(lmFactor),
+                itsBalancedEq(balancedEq),
                 itsUnknowns(unknowns)
         {
         }
-        
+
         uint32 getDomainIndex() const
-        {
-            return itsDomainIndex;
-        }
-    
-        double getEpsilon() const
-        {
-            return itsEpsilon;
-        }
-        
+        { return itsDomainIndex; }
+
         uint32 getMaxIter() const
-        {
-            return itsMaxIter;
-        }
-        
+        { return itsMaxIter; }
+
+        double getEpsilon() const
+        { return itsEpsilon; }
+
+        double getColFactor() const
+        { return itsColFactor; }
+
+        double getLMFactor() const
+        { return itsLMFactor; }
+
+        bool getBalancedEq() const
+        { return itsBalancedEq; }
+
         const vector<double> &getUnknowns() const
-        {
-            return itsUnknowns;
-        }
+        { return itsUnknowns; }
 
         static const string theirClassType;
-   
+
     private:
-        //# -------- BlobStreamable interface implementation -------- 
-    
+        //# -------- BlobStreamable interface implementation --------
+
         // Write the contents of \c *this into the blob output stream \a bos.
         virtual void write(BlobOStream& bos) const;
 
@@ -99,11 +111,14 @@ namespace BBS
 
         // Return the type of \c *this as a string.
         virtual const string& classType() const;
-        
-        //# -------- Attributes -------- 
+
+        //# -------- Attributes --------
         uint32              itsDomainIndex;
-        double              itsEpsilon;
         uint32              itsMaxIter;
+        double              itsEpsilon;
+        double              itsColFactor;
+        double              itsLMFactor;
+        bool                itsBalancedEq;
         vector<double>      itsUnknowns;
     };
 
diff --git a/CEP/BB/BBSControl/include/BBSControl/SolverProcessControl.h b/CEP/BB/BBSControl/include/BBSControl/SolverProcessControl.h
index 7f5191a591a91ae708fbb1eb131255dcc440ff9d..50f0bebcc161502c81ec9268120676402e372929 100644
--- a/CEP/BB/BBSControl/include/BBSControl/SolverProcessControl.h
+++ b/CEP/BB/BBSControl/include/BBSControl/SolverProcessControl.h
@@ -80,11 +80,8 @@ namespace BBS
                 uint32          index;
                 vector<double>  unknowns;
                 casa::LSQFit    solver;
-                //# this attribute is only temporary, until the problems with
-                //# the latest version of LSQFit have been solved.
-                double          epsilon;
             };
-            
+
             bool dispatch(const BlobStreamable *message);
             bool handle(const DomainRegistrationRequest *request);
             bool handle(const BlobStreamableVector<DomainRegistrationRequest> *request);
@@ -93,12 +90,12 @@ namespace BBS
 
             bool registerDomain(const DomainRegistrationRequest *request);
             IterationResult *performIteration(const IterationRequest *request);
-            
+
             // Parameter set for this process controller.
             ACC::APS::ParameterSet itsParameterSet;
 
             scoped_ptr<BlobStreamableConnection> itsKernelConnection;
-            
+
             map<uint32, Domain> itsRegisteredDomains;
         };
     // @}
diff --git a/CEP/BB/BBSControl/src/CommandExecutor.cc b/CEP/BB/BBSControl/src/CommandExecutor.cc
index fd8baac2f7592d3616ca7d39bd78e2699fa7a68f..3a7a78d1db295bddf2bc56a13983d7d6bfa147db 100644
--- a/CEP/BB/BBSControl/src/CommandExecutor.cc
+++ b/CEP/BB/BBSControl/src/CommandExecutor.cc
@@ -52,8 +52,21 @@
 #include <Common/LofarLogger.h>
 #include <Common/Timer.h>
 
-#include <casa/Quanta/Quantum.h>
-#include <casa/Quanta/MVTime.h>
+//#include <casa/Quanta/Quantum.h>
+//#include <casa/Quanta/MVTime.h>
+
+#if 0
+#define NONREADY        casa::LSQFit::NONREADY
+#define SOLINCREMENT    casa::LSQFit::SOLINCREMENT
+#define DERIVLEVEL      casa::LSQFit::DERIVLEVEL
+#define N_ReadyCode     casa::LSQFit::N_ReadyCode
+#else
+#define NONREADY        0
+#define SOLINCREMENT    1
+#define DERIVLEVEL      2
+#define N_ReadyCode     999
+#endif
+
 
 namespace LOFAR
 {
@@ -73,20 +86,6 @@ CommandExecutor::~CommandExecutor()
 }
 
 
-bool CommandExecutor::convertTime(string in, double &out)
-{
-    //# TODO: Convert from default epoch to MS epoch (as it may differ from 
-    //# the default!)
-    casa::Quantum<casa::Double> time;
-
-    if(in.empty() || !casa::MVTime::read(time, in))
-        return false;
-
-    out = static_cast<double>(time.getValue("s"));
-    return true;
-}
-
-
 void CommandExecutor::visit(const InitializeCommand &/*command*/)
 {
     LOG_TRACE_FLOW(AUTO_FUNCTION_NAME);
@@ -98,72 +97,48 @@ void CommandExecutor::visit(const InitializeCommand &/*command*/)
 
     try
     {
-        //# Create a new kernel.
+        // Create a new kernel.
         itsKernel.reset(new Prediffer(strategy->dataSet(),
+//            strategy->subband(),
+            0,
             strategy->inputData(),
             strategy->parmDB().localSky,
             strategy->parmDB().instrument,
             strategy->parmDB().history,
-            0,
+//            strategy->readUVW()));
             false));
     }
-    catch(Exception& e)
+    catch(Exception &ex)
     {
-        LOG_WARN_STR(e);
+        // TODO: get exception msg and put into result msg.
+        itsResult = CommandResult(CommandResult::ERROR, "Could not create"
+            " kernel.");
     }
 
-    //# Select stations and correlations.
-    if(!itsKernel->setSelection(strategy->stations(), strategy->correlation()))
-    {
-        itsResult = CommandResult(CommandResult::ERROR,
-            "Data selection is empty.");
-        return;
-    }
-
-    //# Store chunk size.
-    itsChunkSize = strategy->domainSize().timeInterval;
-
-    LOG_DEBUG_STR("ChunkSize: " << itsChunkSize);
-
-    //# Get Region Of Interest.
+    // Create selection from information in strategy.
     RegionOfInterest roi = strategy->regionOfInterest();
+    Correlation correlation = strategy->correlation();
 
-    //# Get Local Data Domain.
-    MeqDomain ldd = itsKernel->getLocalDataDomain();
-
-    //# Parse and validate time selection.
-    bool start = false, end = false;
+    VisSelection selection;
+    if(!strategy->stations().empty())
+        selection.setStations(strategy->stations());
 
-    start = (roi.time.size() >= 1) && convertTime(roi.time[0], itsROITime[0]);
-    end = (roi.time.size() >= 2) && convertTime(roi.time[1], itsROITime[1]);
+    if(!correlation.type.empty())
+        selection.setCorrelations(correlation.type);
 
-    if(start && end && itsROITime[0] > itsROITime[1])
+    if(correlation.selection == "AUTO")
     {
-        LOG_WARN("Specified start/end times are incorrect; All times will" 
-            " be selected.");
-        start = end = false;
+        selection.setBaselineFilter(VisSelection::AUTO);
     }
+    else if(correlation.selection == "CROSS")
+    {
+        selection.setBaselineFilter(VisSelection::CROSS);
+    }
+    itsKernel->setSelection(selection);
 
-    if(!start || itsROITime[0] <= ldd.startY())
-        itsROITime[0] = ldd.startY();
-
-    if(!end || itsROITime[1] >= ldd.endY())
-        itsROITime[1] = ldd.endY();
-
-    //# Get frequency (channel) selection.
-    itsROIFrequency[0] = itsROIFrequency[0] = -1;
-    if(roi.frequency.size() >= 1)
-        itsROIFrequency[0] = roi.frequency[0];
-    if(roi.frequency.size() >= 2)
-        itsROIFrequency[1] = roi.frequency[1];
-
-    //# Reset chunk iteration.
-    itsChunkPosition = itsROITime[0];
-
-    LOG_DEBUG_STR("Region Of Interest:" << endl
-        << "  + Channels: " << itsROIFrequency[0] << " - " << itsROIFrequency[1]
-        << endl
-        << "  + Time:     " << itsROITime[0] << " - " << itsROITime[1] << endl);
+    size_t size = strategy->domainSize().timeInterval;
+    LOG_DEBUG_STR("Chunk size: " << size << " timeslot(s)");
+    itsKernel->setChunkSize(size);
 
     itsResult = CommandResult(CommandResult::OK, "Ok.");
 }
@@ -186,33 +161,14 @@ void CommandExecutor::visit(const NextChunkCommand &/*command*/)
 
     LOG_DEBUG("Handling a NextChunkCommand");
 
-    //# Iteration should be moved to the kernel code. Ideally, we would only 
-    //# issue an itsKernel->nextChunk() here. However, as this is entangled with 
-    //# the new MS interface, we'll emulate it by setting a new local work 
-    //# domain for now.
-    if(itsChunkPosition >= itsROITime[1])
+    if(itsKernel->nextChunk())
     {
-        LOG_DEBUG_STR("NextChunk: OUT_OF_DATA");
-        itsResult = CommandResult(CommandResult::OUT_OF_DATA);
-        return;
-    }
-
-    double size = itsChunkSize;
-    if(itsChunkPosition + itsChunkSize > itsROITime[1])
-        size = itsROITime[1] - itsChunkPosition;
-
-    if(!itsKernel->setWorkDomain(static_cast<int>(itsROIFrequency[0]),
-        static_cast<int>(itsROIFrequency[1]),
-        itsChunkPosition,
-        size))
-    {
-        itsResult = CommandResult(CommandResult::ERROR,
-            "Could not set work domain.");
+        itsResult = CommandResult(CommandResult::OK, "Ok.");
     }
     else
     {
-        itsChunkPosition += itsChunkSize;
-        itsResult = CommandResult(CommandResult::OK, "Ok.");
+        LOG_DEBUG_STR("NextChunk: OUT_OF_DATA");
+        itsResult = CommandResult(CommandResult::OUT_OF_DATA);
     }
 }
 
@@ -280,7 +236,7 @@ void CommandExecutor::visit(const BBSPredictStep &command)
     }
 
     // Execute predict.
-    itsKernel->predictVisibilities();
+    itsKernel->predict();
     itsResult = CommandResult(CommandResult::OK, "Ok.");
 }
 
@@ -310,7 +266,7 @@ void CommandExecutor::visit(const BBSSubtractStep &command)
     }
 
     // Execute subtract.
-    itsKernel->subtractVisibilities();
+    itsKernel->subtract();
     itsResult = CommandResult(CommandResult::OK, "Ok.");
 }
 
@@ -340,7 +296,7 @@ void CommandExecutor::visit(const BBSCorrectStep &command)
     }
 
     // Execute correct.
-    itsKernel->correctVisibilities();
+    itsKernel->correct();
     itsResult = CommandResult(CommandResult::OK, "Ok.");
 }
 
@@ -365,50 +321,23 @@ void CommandExecutor::visit(const BBSSolveStep &command)
     context.unknowns = command.parms();
     context.excludedUnknowns = command.exclParms();
 
-    // Create solve domains. For now this just splits the work domain in a
-    // rectangular grid, with cells of size command.itsDomainSize. Should 
-    // become more interesting in the near future.
-    const MeqDomain &workDomain = itsKernel->getWorkDomain();
-
-    const int freqCount = (int) ceil((workDomain.endX() -
-        workDomain.startX()) / command.domainSize().bandWidth);
-    const int timeCount = (int) ceil((workDomain.endY() -
-        workDomain.startY()) / command.domainSize().timeInterval);
+/*
+    pair<size_t, size_t> domainSize(command.domainSize().bandWidth,
+        command.domainSize().timeInterval);
 
-    double timeOffset = workDomain.startY();
-    double timeSize = command.domainSize().timeInterval;
-
-    int time = 0;
-    while(time < timeCount)
+    if (domainSize.first != 0)
     {
-        double freqOffset = workDomain.startX();
-        double freqSize = command.domainSize().bandWidth;
-
-        if(timeOffset + timeSize > workDomain.endY())
-        {
-            timeSize = workDomain.endY() - timeOffset;
-        }
-
-        int freq = 0;
-        while(freq < freqCount)
-        {
-            if(freqOffset + freqSize > workDomain.endX())
-            {
-                freqSize = workDomain.endX() - freqOffset;
-            }
-
-            context.solveDomains.push_back(MeqDomain(freqOffset,
-                freqOffset + freqSize,
-                timeOffset,
-                timeOffset + timeSize));
+        LOG_WARN_STR("Subdividing in frequency not support yet; setting"
+            " will be ignored.");
+        domainSize.first = 0;
+    }
 
-            freqOffset += freqSize;
-            freq++;
-        }
+    context.domainSize = domainSize;
+*/
 
-        timeOffset += timeSize;
-        time++;
-    }
+    LOG_WARN_STR("Subdivision specfication not yet implemented; using domains"
+        " of 1 timeslot.");
+    context.domainSize = make_pair(0, 1);
 
     // Set context.
     if(!itsKernel->setContext(context))
@@ -418,154 +347,198 @@ void CommandExecutor::visit(const BBSSolveStep &command)
         return;
     }
 
-    // Register all solve domains with the solver.
-    BlobStreamableVector<DomainRegistrationRequest> request;
+    // Get domain descriptors.
     const vector<SolveDomainDescriptor> &descriptors =
         itsKernel->getSolveDomainDescriptors();
-    for(size_t i = 0; i < descriptors.size(); ++i)
-    {
-        request.getVector().push_back(new DomainRegistrationRequest(
-            i,
-            command.epsilon(),
-            command.maxIter(),
-            descriptors[i].unknowns));
-    }
-    itsSolverConnection->sendObject(request);
 
-    // Main iteration loop.
-    bool finished = false;
-    unsigned int iteration = 1;
-    while(!finished)
+    size_t blockSize = 1;
+    size_t nBlocks =
+        ceil(descriptors.size() / static_cast<double>(blockSize));
+
+    vector<double> solution(descriptors.front().unknowns);
+    vector<casa::LSQFit> solvers(blockSize);
+    size_t convergedTotal = 0, stoppedTotal = 0;
+    for(size_t block = 0; block < nBlocks; ++block)
     {
-        LOG_DEBUG_STR("[START] Iteration: " << iteration);
+        pair<size_t, size_t> domainRange(block * blockSize,
+            (block + 1) * blockSize - 1);
+        if(domainRange.second >= descriptors.size())
+            domainRange.second = descriptors.size() - 1;
+        size_t nDomains = domainRange.second - domainRange.first + 1;
+
+        LOG_DEBUG_STR("Processing domain(s) " << domainRange.first << " - "
+            << domainRange.second << " (" << descriptors.size()
+            << " domain(s) in total)");
+        LOG_DEBUG_STR("Initial values: " << solution);
+
+        // Register all solve domains with the solver.
+        BlobStreamableVector<DomainRegistrationRequest> request;
+        for(size_t i = domainRange.first; i <= domainRange.second; ++i)
+        {
+            itsKernel->updateSolvableParms(i, solution);
+            request.getVector().push_back(new DomainRegistrationRequest(i,
+                solution,
+                command.maxIter(),
+                command.epsilon()));
+        }
+        itsSolverConnection->sendObject(request);
 
-        LOG_DEBUG_STR("[START] Generating normal equations...");
-        timer.reset();
-        timer.start();
+        // Main iteration loop.
+        bool finished = false;
+        size_t iteration = 1, converged = 0, stopped = 0;
+        while(!finished)
+        {
+            LOG_DEBUG_STR("[START] Iteration: " << iteration);
+            LOG_DEBUG_STR("[START] Generating normal equations...");
+            timer.reset();
+            timer.start();
 
-        // Generate normal equations.
-        vector<casa::LSQFit> equations;
-        itsKernel->generateEquations(equations);
+            // Generate normal equations.
+            itsKernel->generate(make_pair(0, domainRange.first),
+                make_pair(0, domainRange.second), solvers);
 
-        timer.stop();
-        LOG_DEBUG_STR("[END  ] Generating normal equations; " << timer);
+            timer.stop();
+            LOG_DEBUG_STR("[ END ] Generating normal equations; " << timer);
 
-        LOG_DEBUG_STR("[START] Sending equations to solver and waiting for"
-            " results...");
-        timer.reset();
-        timer.start();
 
-        // Send iteration requests to the solver in one go.
-        BlobStreamableVector<IterationRequest> iterationRequests;
-        for(size_t i = 0; i < equations.size(); ++i)
-        {
-            iterationRequests.getVector().push_back(new IterationRequest(i,
-                equations[i]));
-        }
-        itsSolverConnection->sendObject(iterationRequests);
+            LOG_DEBUG_STR("[START] Sending equations to solver and waiting"
+                " for results...");
+            timer.reset();
+            timer.start();
 
-        BlobStreamableVector<IterationResult> *resultv =
-            dynamic_cast<BlobStreamableVector<IterationResult>*>(
-                itsSolverConnection->recvObject());
-        ASSERT(resultv);
+            // Send iteration requests to the solver in one go.
+            BlobStreamableVector<IterationRequest> iterationRequests;
+            for(size_t i = 0; i < nDomains; ++i)
+            {
+                iterationRequests.getVector().push_back(
+                    new IterationRequest(domainRange.first + i,
+                        solvers[i]));
+            }
+            itsSolverConnection->sendObject(iterationRequests);
 
-        timer.stop();
-        LOG_DEBUG_STR("[END ] Sending/waiting; " << timer);
+            BlobStreamableVector<IterationResult> *resultv =
+                dynamic_cast<BlobStreamableVector<IterationResult>*>(
+                    itsSolverConnection->recvObject());
 
-        LOG_DEBUG_STR("[START] Processing results...");
-        timer.reset();
-        timer.start();
+            ASSERT(resultv);
 
-        const vector<IterationResult*> &results = resultv->getVector();
+            timer.stop();
+            LOG_DEBUG_STR("[ END ] Sending/waiting; " << timer);
 
+            LOG_DEBUG_STR("[START] Processing results...");
+            timer.reset();
+            timer.start();
 
-        // For each solve domain:
-        //     - wait for result
-        //     - check for convergence
-        //     - update cached values of the unknowns
-        unsigned int converged = 0/*, stopped = 0*/;
-        for(size_t i = 0; i < results.size(); ++i)
-        {
-            const IterationResult *result = results[i];
-
-            // Check for convergence.
-            if(result->getResultCode() != 0)
-                converged++;
-
-//                if(result->getResultCode() != casa::LSQFit::NONREADY)
-//                {
-//                    if(result->getResultCode() == casa::LSQFit::SOLINCREMENT
-//||
-//                        result->getResultCode() == casa::LSQFit::DERIVLEVEL)
-//                    {
-//                        converged++;
-//                    }
-//                    else
-//                        stopped++;
-//                }
-
-//                LOG_DEBUG_STR("+ Domain: " << result->getDomainIndex());
-                //LOG_DEBUG_STR("  + result: " << result->getResultCode() <<
-                //              ", " << result->getResultText());
-//                LOG_DEBUG_STR("  + rank: " << result->getRank() <<
-//                            ", chi^2: " << result->getChiSquared() <<
-//                            ", LM factor: " << result->getLMFactor());
-//                LOG_DEBUG_STR("  + unknowns: " << result->getUnknowns());
-
-            if(result->getResultCode() != 2)
+            const vector<IterationResult*> &results = resultv->getVector();
+
+            // For each solve domain:
+            //     - check for convergence
+            //     - update cached values of the unknowns
+            converged = stopped = 0;
+            for(size_t i = 0; i < results.size(); ++i)
             {
+                const IterationResult *result = results[i];
+                size_t resultCode = result->getResultCode();
+
+                if(resultCode == NONREADY)
+                {
+                    // Update cached values of the unknowns.
+                    itsKernel->updateSolvableParms(
+                        result->getDomainIndex(),
+                        result->getUnknowns());
+/*
+                    // Log the updated unknowns.
+                    itsKernel->logIteration(
+                        command.getName(),
+                        startDomain + i,
+                        result->getRank(),
+                        result->getChiSquared(),
+                        result->getLMFactor());
+*/
+
 #ifdef LOG_SOLVE_DOMAIN_STATS
-                LOG_DEBUG_STR("Domain: " << result->getDomainIndex()
-                    << ", Rank: " << result->getRank()
-                    << ", Chi^2: " << result->getChiSquared()
-                    << ", LM factor: " << result->getLMFactor());
+                    LOG_DEBUG_STR("Domain: " << result->getDomainIndex()
+                        << ", Rank: " << result->getRank()
+                        << ", Chi^2: " << result->getChiSquared()
+                        << ", LM factor: " << result->getLMFactor()
+                        << ", Message: " << result->getResultText());
 #endif
-                // Update cached values of the unknowns.
-                itsKernel->updateSolvableParms(i, result->getUnknowns());
-
-                // Log the updated unknowns.
-                itsKernel->logIteration(
-                    command.getName(),
-                    i,
-                    result->getRank(),
-                    result->getChiSquared(),
-                    result->getLMFactor());
+                }
+                else if(resultCode == SOLINCREMENT
+                        || resultCode == DERIVLEVEL
+                        || resultCode == N_ReadyCode)
+                {
+                    converged++;
+                }
+                else
+                {
+                    stopped++;
+                }
             }
-#ifdef LOG_SOLVE_DOMAIN_STATS
-            else
-                LOG_DEBUG_STR("Domain: " << result->getDomainIndex()
-                    << " - Already converged");
-#endif
+
+            if(results.back()->getResultCode() == NONREADY)
+            {
+                // Save solution of last solve domain in this block.
+                solution = results.back()->getUnknowns();
+            }
+
+            delete resultv;
+
+            timer.stop();
+            LOG_DEBUG_STR("[ END ] Processing results; " << timer);
+
+            LOG_DEBUG_STR("[ END ] Iteration: " << iteration);
+
+
+            ostringstream oss;
+            oss << "Block statistics: " << endl;
+            oss << "    converged: " << converged << "/" << nDomains
+                << " (" << (((double) converged) / nDomains * 100.0) << "%)"
+                << endl;
+            oss << "    stopped  : " << stopped << "/" << nDomains
+                << " (" << (((double) stopped) / nDomains * 100.0) << "%)";
+            LOG_DEBUG(oss.str());
+            //finished = (converged + stopped ==
+            // context.solveDomains.size()) || (converged>=
+            //(command.minConverged() *
+            //context.solveDomains.size()) / 100.0);
+
+            finished = ((converged + stopped) == nDomains)
+                || (iteration == command.maxIter());
+            iteration++;
         }
-        timer.stop();
-        LOG_DEBUG_STR("[END  ] Processing results; " << timer);
-
-        LOG_DEBUG_STR("[END  ] Iteration: " << iteration
-            << ", Solve domains converged: " << converged << "/"
-            << context.solveDomains.size()
-            << " (" << (((double) converged) / context.solveDomains.size() *
-            100.0) << "%)");
-        //LOG_INFO_STR("Solve domains stopped: " << stopped << "/" <<
-        //context.solveDomains.size() << " (" << (((double) stopped) /
-        //context.solveDomains.size() * 100.0) << "%)");
-
-        delete resultv;
-        //finished = (converged + stopped == context.solveDomains.size()) ||
-        //    (converged>= (command.minConverged() *
-        //      context.solveDomains.size()) / 100.0);
-        finished = (converged == context.solveDomains.size())
-            || (iteration == command.maxIter());
-        iteration++;
-    }
 
-    LOG_DEBUG_STR("[START] Writing solutions into parameter databases...");
-    timer.reset();
-    timer.start();
+        convergedTotal += converged;
+        stoppedTotal += stopped;
+
+        ostringstream oss;
+        oss << "Global statistics: " << endl;
+        oss << "    converged: " << convergedTotal << "/"
+            << descriptors.size() << " ("
+            << (((double) convergedTotal) / descriptors.size() * 100.0)
+            << "%)" << endl;
+        oss << "    stopped  : " << stoppedTotal << "/"
+            << descriptors.size() << " ("
+            << (((double) stoppedTotal) / descriptors.size() * 100.0)
+            << "%)";
+        LOG_DEBUG(oss.str());
+
+        LOG_DEBUG_STR("[START] Writing solutions into parameter"
+            " databases...");
+        timer.reset();
+        timer.start();
 
-    itsKernel->writeParms();
+        for(size_t i = domainRange.first; i <= domainRange.second; ++i)
+        {
+            itsKernel->writeParms(i);
+        }
+
+        timer.stop();
+        LOG_DEBUG_STR("[ END ] Writing solutions; " << timer);
+    }
 
-    timer.stop();
-    LOG_DEBUG_STR("[END  ] Writing solutions; " << timer);
+    // Try to force log4cplus to flush its buffers.
+    cout << "DONE." << endl;
 
     itsResult = CommandResult(CommandResult::OK, "Ok.");
 }
diff --git a/CEP/BB/BBSControl/src/DomainRegistrationRequest.cc b/CEP/BB/BBSControl/src/DomainRegistrationRequest.cc
index 96f9ea2bb510b7cd95943429185f873e05a4bed4..0736f89f1aa38f853a775123f2ee2fc470cfd021 100644
--- a/CEP/BB/BBSControl/src/DomainRegistrationRequest.cc
+++ b/CEP/BB/BBSControl/src/DomainRegistrationRequest.cc
@@ -38,7 +38,7 @@ namespace BBS
     using LOFAR::operator>>;
 
     const string DomainRegistrationRequest::theirClassType = "DomainRegistrationRequest";
-    
+
     // Register DomainRegistrationRequest with the BlobStreamableFactory. Use an anonymous
     // namespace. This ensures that the variable `dummy' gets its own private
     // storage area and is only visible in this compilation unit.
@@ -47,14 +47,17 @@ namespace BBS
         bool dummy = BlobStreamableFactory::instance().registerClass<DomainRegistrationRequest>("DomainRegistrationRequest");
         bool dummy_vector = BlobStreamableFactory::instance().registerClass<BlobStreamableVector<DomainRegistrationRequest> >("BlobStreamableVector<" + DomainRegistrationRequest::theirClassType + ">");
     }
-    
+
     void DomainRegistrationRequest::write(BlobOStream& bos) const
     {
         LOG_TRACE_LIFETIME(TRACE_LEVEL_RTTI, "");
-        
+
         bos << itsDomainIndex
-            << itsEpsilon
             << itsMaxIter
+            << itsEpsilon
+            << itsColFactor
+            << itsLMFactor
+            << itsBalancedEq
             << itsUnknowns;
     }
 
@@ -62,10 +65,13 @@ namespace BBS
     void DomainRegistrationRequest::read(BlobIStream& bis)
     {
         LOG_TRACE_LIFETIME(TRACE_LEVEL_RTTI, "");
-        
+
         bis >> itsDomainIndex
-            >> itsEpsilon
             >> itsMaxIter
+            >> itsEpsilon
+            >> itsColFactor
+            >> itsLMFactor
+            >> itsBalancedEq
             >> itsUnknowns;
     }
 
diff --git a/CEP/BB/BBSControl/src/GlobalProcessControl.cc b/CEP/BB/BBSControl/src/GlobalProcessControl.cc
index eb86b36fd36fa13e36351aa51473ccf68627e45e..5dcc96e505eda13b03b266448e597f5dc7174de1 100644
--- a/CEP/BB/BBSControl/src/GlobalProcessControl.cc
+++ b/CEP/BB/BBSControl/src/GlobalProcessControl.cc
@@ -98,10 +98,13 @@ namespace LOFAR
       LOG_INFO("GlobalProcessControl::init()");
 
       try {
-	// Create a new CommandQueue. This will open a connection to the
-	// blackboard database.
-	itsCommandQueue.reset
-          (new CommandQueue(globalParameterSet()->getString("BBDB.DBName")));
+        // Create a new CommandQueue. This will open a connection to the
+        // blackboard database.
+        itsCommandQueue.reset
+          (new CommandQueue(globalParameterSet()->getString("BBDB.DBName"),
+          globalParameterSet()->getString("BBDB.UserName"),
+          globalParameterSet()->getString("BBDB.Host"),
+          globalParameterSet()->getString("BBDB.Port")));
 
         // Register for the "result" trigger, which fires when a new result is
         // posted to the blackboard database.
diff --git a/CEP/BB/BBSControl/src/KernelProcessControl.cc b/CEP/BB/BBSControl/src/KernelProcessControl.cc
index 61f5f91fccfe2cbf389ed2cd8447b734af304f26..bf0c5ba98bd805dd37caf4dc9ed146858608767a 100644
--- a/CEP/BB/BBSControl/src/KernelProcessControl.cc
+++ b/CEP/BB/BBSControl/src/KernelProcessControl.cc
@@ -126,7 +126,10 @@ namespace BBS
             // Create a new CommandQueue. This will open a connection to the
             // blackboard database.
             itsCommandQueue.reset(new CommandQueue(
-                globalParameterSet()->getString("BBDB.DBName")));
+                globalParameterSet()->getString("BBDB.DBName"),
+                globalParameterSet()->getString("BBDB.UserName"),
+                globalParameterSet()->getString("BBDB.Host"),
+                globalParameterSet()->getString("BBDB.Port")));
 
             // Register for the "command" trigger, which fires when a new
             // command is posted to the blackboard database.
diff --git a/CEP/BB/BBSControl/src/SolverProcessControl.cc b/CEP/BB/BBSControl/src/SolverProcessControl.cc
index 9874903653982073de712c5ea2d07998414e9de3..103e42484a4bf4f5623fc5eb10a912780462379b 100644
--- a/CEP/BB/BBSControl/src/SolverProcessControl.cc
+++ b/CEP/BB/BBSControl/src/SolverProcessControl.cc
@@ -39,326 +39,326 @@
 
 #include <stdlib.h>
 
+#if 0
+    #define NONREADY        casa::LSQFit::NONREADY
+    #define N_ReadyCode     casa::LSQFit::N_ReadyCode
+    #define SUMLL           casa::LSQFit::SUMLL
+    #define NC              casa::LSQFit::NC
+#else
+    #define NONREADY        0
+    #define N_ReadyCode     999
+    #define NC              0
+    #define SUMLL           2
+#endif
+
 using namespace LOFAR::ACC::APS;
 
-namespace LOFAR 
+namespace LOFAR
 {
-namespace BBS 
+namespace BBS
 {
-    using LOFAR::operator<<;
-    using boost::scoped_ptr;
+using LOFAR::operator<<;
+using boost::scoped_ptr;
 
+//# Ensure classes are registered with the ObjectFactory.
+template class BlobStreamableVector<DomainRegistrationRequest>;
+template class BlobStreamableVector<IterationRequest>;
+template class BlobStreamableVector<IterationResult>;
 
-    //# Ensure classes are registered with the ObjectFactory.
-    template class BlobStreamableVector<DomainRegistrationRequest>;
-    template class BlobStreamableVector<IterationRequest>;
-    template class BlobStreamableVector<IterationResult>;
 
+//##----   P u b l i c   m e t h o d s   ----##//
+SolverProcessControl::SolverProcessControl()
+    :   ProcessControl()
+{
+    LOG_TRACE_FLOW(AUTO_FUNCTION_NAME);
+}
 
-    //##----   P u b l i c   m e t h o d s   ----##//
-    SolverProcessControl::SolverProcessControl() :
-        ProcessControl()
-    {
-        LOG_TRACE_FLOW(AUTO_FUNCTION_NAME);
-    }
 
+SolverProcessControl::~SolverProcessControl()
+{
+    LOG_TRACE_FLOW(AUTO_FUNCTION_NAME);
+}
 
-    SolverProcessControl::~SolverProcessControl()
-    {
-        LOG_TRACE_FLOW(AUTO_FUNCTION_NAME);
-    }
 
+tribool SolverProcessControl::define()
+{
+    LOG_TRACE_FLOW(AUTO_FUNCTION_NAME);
 
-    tribool SolverProcessControl::define()
+    try
     {
-        LOG_INFO("SolverProcessControl::define()");
-        
-        try
-        {
-            char *user = getenv("USER");
-            ASSERT(user);
-            string userString(user);
-            
-            itsKernelConnection.reset(new BlobStreamableConnection(
-                "=Solver_" + userString,
-                Socket::LOCAL));
-        }
-        catch(Exception& e)
-        {
-            LOG_ERROR_STR(e);
-            return false;
-        }
-        
-        return true;
-    }
-
+        char *user = getenv("USER");
+        ASSERT(user);
+        string userString(user);
 
-    tribool SolverProcessControl::init()
+        itsKernelConnection.reset(new BlobStreamableConnection(
+            "=Solver_" + userString,
+            Socket::LOCAL));
+    }
+    catch(Exception& e)
     {
-        LOG_INFO("SolverProcessControl::init()");
-        try
-        {
-            LOG_INFO("Starting to listen at solver@localhost");
-            if(!itsKernelConnection->connect())
-            {
-                LOG_ERROR("+ listen failed");
-                return false;
-            }
-            LOG_INFO("+ ok");
-        }
-        catch(Exception& e)
-        {
-            LOG_ERROR_STR(e);
-            return false;
-        }
-        
-        // All went well.
-        return true;
+        LOG_ERROR_STR(e);
+        return false;
     }
 
+    return true;
+}
 
-    tribool SolverProcessControl::run()
-    {
-        LOG_INFO("SolverProcessControl::run()");
 
-        try
-        {
-            // Receive the next message
-            scoped_ptr<BlobStreamable> message(itsKernelConnection->recvObject());
-            if(message)
-                return dispatch(message.get());
-            else
-                return false;
-        }
-        catch(Exception& e)
+tribool SolverProcessControl::init()
+{
+    LOG_TRACE_FLOW(AUTO_FUNCTION_NAME);
+
+    try
+    {
+        LOG_INFO("Listening at solver@localhost");
+        if(!itsKernelConnection->connect())
         {
-            LOG_ERROR_STR(e);
+            LOG_ERROR("+ listen failed");
             return false;
         }
+        LOG_INFO("+ ok");
     }
-
-
-    tribool SolverProcessControl::pause(const string& /*condition*/)
+    catch(Exception& e)
     {
-        LOG_TRACE_FLOW(AUTO_FUNCTION_NAME);
-        LOG_WARN("Not supported");
+        LOG_ERROR_STR(e);
         return false;
     }
 
+    // All went well.
+    return true;
+}
 
-    tribool SolverProcessControl::quit()
-    {
-        LOG_INFO("SolverProcessControl::quit()");
-        return true;
-    }
 
+tribool SolverProcessControl::run()
+{
+    LOG_TRACE_FLOW(AUTO_FUNCTION_NAME);
 
-    tribool SolverProcessControl::snapshot(const string& /*destination*/)
+    try
     {
-        LOG_TRACE_FLOW(AUTO_FUNCTION_NAME);
-        LOG_WARN("Not supported");
-        return false;
+        // Receive the next message
+        scoped_ptr<BlobStreamable> message(itsKernelConnection->recvObject());
+        if(message)
+            return dispatch(message.get());
+        else
+            return false;
     }
-
-
-    tribool SolverProcessControl::recover(const string& /*source*/)
+    catch(Exception& e)
     {
-        LOG_TRACE_FLOW(AUTO_FUNCTION_NAME);
-        LOG_WARN("Not supported");
+        LOG_ERROR_STR(e);
         return false;
     }
+}
 
 
-    tribool SolverProcessControl::reinit(const string& /*configID*/)
-    {
-        LOG_TRACE_FLOW(AUTO_FUNCTION_NAME);
-        LOG_WARN("Not supported");
-        return false;
-    }
+tribool SolverProcessControl::pause(const string& /*condition*/)
+{
+    LOG_TRACE_FLOW(AUTO_FUNCTION_NAME);
+    LOG_WARN("Not supported");
+    return false;
+}
 
 
-    std::string SolverProcessControl::askInfo(const string& /*keylist*/)
-    {
-        LOG_TRACE_FLOW(AUTO_FUNCTION_NAME);
-        return std::string("");
-    }
+tribool SolverProcessControl::quit()
+{
+    LOG_TRACE_FLOW(AUTO_FUNCTION_NAME);
+    return true;
+}
+
+
+tribool SolverProcessControl::snapshot(const string& /*destination*/)
+{
+    LOG_TRACE_FLOW(AUTO_FUNCTION_NAME);
+    LOG_WARN("Not supported");
+    return false;
+}
+
+
+tribool SolverProcessControl::recover(const string& /*source*/)
+{
+    LOG_TRACE_FLOW(AUTO_FUNCTION_NAME);
+    LOG_WARN("Not supported");
+    return false;
+}
+
+
+tribool SolverProcessControl::reinit(const string& /*configID*/)
+{
+    LOG_TRACE_FLOW(AUTO_FUNCTION_NAME);
+    LOG_WARN("Not supported");
+    return false;
+}
+
+
+std::string SolverProcessControl::askInfo(const string& /*keylist*/)
+{
+    LOG_TRACE_FLOW(AUTO_FUNCTION_NAME);
+    return std::string("");
+}
 
 
-    bool SolverProcessControl::dispatch(const BlobStreamable *message)
+bool SolverProcessControl::dispatch(const BlobStreamable *message)
+{
     {
-        {
-            const DomainRegistrationRequest *request = dynamic_cast<const DomainRegistrationRequest*>(message);
-            if(request)
-                return handle(request);
-        }
-        
-        {
-            const BlobStreamableVector<DomainRegistrationRequest> *request = dynamic_cast<const BlobStreamableVector<DomainRegistrationRequest>*>(message);
-            if(request)
-                return handle(request);
-        }
-        
-        {
-            const IterationRequest *request = dynamic_cast<const IterationRequest*>(message);
-            if(request)
-                return handle(request);
-        }
-        
-        {
-            const BlobStreamableVector<IterationRequest> *request = dynamic_cast<const BlobStreamableVector<IterationRequest>*>(message);
-            if(request)
-                return handle(request);
-        }
-        
-        // We received a message we can't handle
-        LOG_WARN_STR("Received message of unsupported type");
-        return false;
+        const DomainRegistrationRequest *request =
+            dynamic_cast<const DomainRegistrationRequest*>(message);
+        if(request)
+            return handle(request);
     }
-    
-    
-    bool SolverProcessControl::handle(const DomainRegistrationRequest *request)
+
     {
-        return registerDomain(request);
+        const BlobStreamableVector<DomainRegistrationRequest> *request =
+            dynamic_cast<const BlobStreamableVector<DomainRegistrationRequest>*>
+                (message);
+        if(request)
+            return handle(request);
     }
 
-    
-    bool SolverProcessControl::handle(const BlobStreamableVector<DomainRegistrationRequest> *request)
     {
-        bool result = true;
-        for(vector<DomainRegistrationRequest*>::const_iterator it = request->getVector().begin();
-            it != request->getVector().end() && result;
-            ++it)
-        {
-            result = result && registerDomain(*it);
-        }
-        return result;
+        const IterationRequest *request =
+            dynamic_cast<const IterationRequest*>(message);
+        if(request)
+            return handle(request);
     }
-    
-    
-    bool SolverProcessControl::handle(const IterationRequest *request)
+
     {
-        scoped_ptr<IterationResult> result(performIteration(request));
-        return itsKernelConnection->sendObject(*result.get());
+        const BlobStreamableVector<IterationRequest> *request =
+            dynamic_cast<const BlobStreamableVector<IterationRequest>*>
+                (message);
+        if(request)
+            return handle(request);
     }
 
+    // We received a message we can't handle
+    LOG_WARN_STR("Received message of unsupported type");
+    return false;
+}
+
+
+bool SolverProcessControl::handle(const DomainRegistrationRequest *request)
+{
+    return registerDomain(request);
+}
+
 
-    bool SolverProcessControl::handle(const BlobStreamableVector<IterationRequest> *request)
+bool SolverProcessControl::handle
+    (const BlobStreamableVector<DomainRegistrationRequest> *request)
+{
+    bool result = true;
+
+    for(vector<DomainRegistrationRequest*>::const_iterator it =
+        request->getVector().begin();
+        it != request->getVector().end() && result;
+        ++it)
     {
-        BlobStreamableVector<IterationResult> result;
-        
-        for(vector<IterationRequest*>::const_iterator it = request->getVector().begin();
-            it != request->getVector().end();
-            ++it)
-        {
-            result.getVector().push_back(performIteration(*it));
-        }
-        
-        return itsKernelConnection->sendObject(result);
+        result = result && registerDomain(*it);
     }
-    
-    
-    bool SolverProcessControl::registerDomain(const DomainRegistrationRequest *request)
+    return result;
+}
+
+
+bool SolverProcessControl::handle(const IterationRequest *request)
+{
+    scoped_ptr<IterationResult> result(performIteration(request));
+    return itsKernelConnection->sendObject(*result.get());
+}
+
+
+bool SolverProcessControl::handle
+    (const BlobStreamableVector<IterationRequest> *request)
+{
+    BlobStreamableVector<IterationResult> result;
+
+    for(vector<IterationRequest*>::const_iterator it =
+        request->getVector().begin();
+        it != request->getVector().end();
+        ++it)
     {
-        LOG_DEBUG_STR("DomainRegistrationRequest: index: " << request->getDomainIndex() << " #unknowns: " << request->getUnknowns().size());
-        LOG_DEBUG_STR("+ unknowns: " << request->getUnknowns());
-        
-        Domain &domain = itsRegisteredDomains[request->getDomainIndex()];
-        domain.index = request->getDomainIndex();
-        domain.unknowns = request->getUnknowns();
-        domain.solver.set(casa::uInt(domain.unknowns.size()));
-        domain.epsilon = request->getEpsilon();
-        // Set new value solution test
-        //domain.solver.setEpsValue(request->getEpsilon());
-        // Set new 'derivative' test (actually, the inf norm of the known
-        // vector is checked).
-        //domain.solver.setEpsDerivative(request->getEpsilon());
-        // Set maximum number of iterations
-        //domain.solver.setMaxIter(request->getMaxIter());
-        // Set new factors (collinearity factor, and Levenberg-Marquardt LMFactor)
-        // void set(Double factor=1e-6, Double LMFactor=1e-3);
-        return true;
+        result.getVector().push_back(performIteration(*it));
     }
 
-        
-    IterationResult *SolverProcessControl::performIteration(const IterationRequest *request)
-    {
-        map<uint32, Domain>::iterator it = itsRegisteredDomains.find(request->getDomainIndex());
-        //ASSERT(it != itsRegisteredDomains.end());
-        if(it == itsRegisteredDomains.end())
-        {
-            // Artifact of the current implementation: equations are still being generated
-            // and send even if the solve domain has already converged. So, we'll just return
-            // a result with resultCode 2 (i.e. already converged).
-            return new IterationResult(
-                request->getDomainIndex(),
-                2,
-                "",
-                vector<double>(),
-                0,
-                -1.0,
-                -1.0);
-        }
+    return itsKernelConnection->sendObject(result);
+}
 
-        // Set the new normal equations.
-        Domain &domain = it->second;
-        domain.solver.merge(request->getNormalEquations());
-
-        // Get some statistics from the solver. Note that the chi squared is
-        // valid for the _previous_ iteration. The solver cannot compute the
-        // chi squared directly after an iteration, because it needs the new
-        // condition equations for that and these are computed by the kernel.
-        double chiSquared, lmFactor;
-        casa::uInt rank, nun, np, ncon, ner, *piv;
-//        casa::Double *nEq, *known, *constr, *er, *sEq, *sol, prec, nonlin;
-        casa::Double *nEq, *known, *constr, *er, *sEq, *sol, prec, nonlin, fit;
-
-        domain.solver.debugIt(nun, np, ncon, ner, rank, nEq, known, constr, er, piv, sEq, sol, prec, nonlin);
-//        ASSERT(er && ner > casa::LSQFit::NC && ner > casa::LSQFit::SUMLL);
-        ASSERT(er && ner > 2);
-        //# It's weird that er[casa::LSQFit::SUMLL] contains chi squared while
-        //# er[casa::LSQFit::CHI2] does not. ??
-        //chiSquared = (er[casa::LSQFit::NC] > 0 ? er[casa::LSQFit::SUMLL] / er[casa::LSQFit::NC] : er[casa::LSQFit::SUMLL]);
-//        chiSquared = er[casa::LSQFit::SUMLL];
-        chiSquared = er[2];
-        lmFactor = nonlin;
-
-        //LOG_DEBUG_STR("before " << domain.unknowns);
-        
-        // Solve the normal equations.
-//        domain.solver.solveLoop(rank, &(domain.unknowns[0]), true);
-        domain.solver.solveLoop(fit, rank, &(domain.unknowns[0]), true);
-        
-        //LOG_DEBUG_STR("after " << domain.unknowns);
-
-        uint32 resultCode = 0;
-        if(fit < 0.0 && abs(fit) < domain.epsilon)
-            //# Force convergence (BBSKernelProcessControl is already geared
-            //# towards the new interface)
-            resultCode = 1;
-        
-        // Send the result to the kernel.
-        IterationResult *result = new IterationResult(
-            request->getDomainIndex(),
-//            domain.solver.isReady(),
-//            domain.solver.readyText(),
-            resultCode,
-            "",
-            domain.unknowns,
-            rank,
-            chiSquared,
-            lmFactor);
-        
-        
-        // If we're done with this domain, unregister it.
-//        if(domain.solver.isReady() != casa::LSQFit::NONREADY)
-        if(resultCode != 0)
-        {
-            LOG_DEBUG_STR("Unregistering domain " << request->getDomainIndex());
-            itsRegisteredDomains.erase(request->getDomainIndex());
-        }
 
-        return result;
+bool SolverProcessControl::registerDomain
+    (const DomainRegistrationRequest *request)
+{
+    LOG_DEBUG_STR("DomainRegistrationRequest: index: "
+        << request->getDomainIndex() << " #unknowns: "
+        << request->getUnknowns().size());
+    LOG_DEBUG_STR("+ unknowns: " << request->getUnknowns());
+
+    Domain &domain = itsRegisteredDomains[request->getDomainIndex()];
+    domain.index = request->getDomainIndex();
+    domain.unknowns = request->getUnknowns();
+    domain.solver.set(casa::uInt(domain.unknowns.size()));
+    // Set new value solution test
+    domain.solver.setEpsValue(request->getEpsilon());
+    // Set new 'derivative' test (actually, the inf norm of the known
+    // vector is checked).
+    domain.solver.setEpsDerivative(request->getEpsilon());
+    // Set maximum number of iterations
+    domain.solver.setMaxIter(request->getMaxIter());
+    // Set new factors (collinearity factor, and Levenberg-Marquardt LMFactor)
+    domain.solver.set(request->getColFactor(), request->getLMFactor());
+    domain.solver.setBalanced(request->getBalancedEq());
+    return true;
+}
+
+
+IterationResult* SolverProcessControl::performIteration
+    (const IterationRequest *request)
+{
+    map<uint32, Domain>::iterator it =
+        itsRegisteredDomains.find(request->getDomainIndex());
+
+    if(it == itsRegisteredDomains.end())
+    {
+        // Artifact of the current implementation: equations are still being
+        // generated and send even if the solve domain has already
+        // converged. So, we'll just return a result with resultCode N_ReadyCode
+        // (i.e. already converged).
+        return new IterationResult(request->getDomainIndex(),
+            N_ReadyCode, "", vector<double>(), 0, -1.0, -1.0);
+    }
+
+    // Set the new normal equations.
+    Domain &domain = it->second;
+    domain.solver.merge(request->getNormalEquations());
+
+    // Get some statistics from the solver. Note that the chi squared is
+    // valid for the _previous_ iteration. The solver cannot compute the
+    // chi squared directly after an iteration, because it needs the new
+    // condition equations for that and these are computed by the kernel.
+    casa::uInt rank, nun, np, ncon, ner, *piv;
+    casa::Double *nEq, *known, *constr, *er, *sEq, *sol, prec, nonlin;
+    domain.solver.debugIt(nun, np, ncon, ner, rank, nEq, known, constr, er,
+        piv, sEq, sol, prec, nonlin);
+    ASSERT(er && ner > SUMLL);
+
+    double lmFactor = nonlin;
+    double chiSquared = er[SUMLL] / std::max(er[NC] + nun, 1.0);
+
+    // Solve the normal equations.
+    domain.solver.solveLoop(rank, &(domain.unknowns[0]), true);
+
+    // Construct a result.
+    IterationResult *result = new IterationResult(domain.index,
+        domain.solver.isReady(),
+        domain.solver.readyText(),
+        domain.unknowns,
+        rank,
+        chiSquared,
+        lmFactor);
+
+    // If we're done with this domain, unregister it.
+    if(domain.solver.isReady() != NONREADY)
+    {
+        itsRegisteredDomains.erase(request->getDomainIndex());
     }
 
+    return result;
+}
+
 } // namespace BBS
 } // namespace LOFAR
diff --git a/CEP/BB/BBSKernel/include/BBSKernel/Axis.h b/CEP/BB/BBSKernel/include/BBSKernel/Axis.h
new file mode 100644
index 0000000000000000000000000000000000000000..950d16de617d0101788f5bdce0b41ae0d550b204
--- /dev/null
+++ b/CEP/BB/BBSKernel/include/BBSKernel/Axis.h
@@ -0,0 +1,181 @@
+//# Axis.h:
+//#
+//# Copyright (C) 2007
+//# ASTRON (Netherlands Foundation for Research in Astronomy)
+//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//# This program 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 2 of the License, or
+//# (at your option) any later version.
+//#
+//# This program 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 this program; if not, write to the Free Software
+//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//# $Id$
+
+#ifndef LOFAR_BBS_BBSKERNEL_GRID_H
+#define LOFAR_BBS_BBSKERNEL_GRID_H
+
+#include <Common/lofar_vector.h>
+#include <algorithm>
+#include <functional>
+#include <utility>
+
+namespace LOFAR
+{
+namespace BBS
+{
+using std::unary_function;
+using std::pair;
+using std::make_pair;
+using std::max;
+using std::min;
+
+/*
+template <typename T>
+class BoundingBox
+{
+    BoundingBox(T minx, T miny, T maxx, T maxy)
+        :   min(minx, miny),
+            max(maxx, maxy)
+    {}
+
+    pair<T, T>      min;
+    pair<T, T>      max;
+}
+
+template <typename T>
+BoudingBox union(const BoundingBox<T> &a, const BoundingBox<T> &b)
+{
+    return BoundingBox(min(a.min.first, b.min.first),
+        min(a.min.second, b.min.second),
+        max(a.max.first, b.max.first),
+        max(a.max.second, b.max.second));
+}
+*/
+
+class regular_series: public unary_function<size_t, double>
+{
+public:
+    regular_series()
+        :   m_begin(0.0),
+            m_delta(1.0)
+    {}
+
+    regular_series(result_type begin, result_type delta)
+        :   m_begin(begin),
+            m_delta(delta)
+    {}
+
+    result_type operator()(argument_type n) const
+    { return m_begin + n * m_delta; }
+ 
+private:
+    result_type    m_begin, m_delta;
+};
+
+
+class irregular_series: public unary_function<size_t, double>
+{
+public:
+    irregular_series()
+    {}
+
+    irregular_series(const vector<result_type> &terms)
+        : m_terms(terms)
+    {}
+
+    result_type operator()(argument_type n) const
+    { return m_terms[n]; }
+
+private:
+    vector<result_type>    m_terms;
+};
+
+
+template <typename SeriesType>
+class cell_centered_axis
+{
+public:
+    cell_centered_axis()
+        :   m_series(SeriesType()),
+            m_size(0)
+    {}
+
+    cell_centered_axis(SeriesType series, size_t size)
+        :   m_series(series),
+            m_size(size)
+    {}
+
+    double operator()(size_t n) const
+    { return 0.5 * (m_series(n) + m_series(n + 1)); }
+
+    double lower(size_t n) const
+    { return m_series(n); }
+
+    double upper(size_t n) const
+    { return m_series(n + 1); }
+
+    double width(size_t n) const
+    { return m_series(n + 1) - m_series(n); }
+
+    size_t size() const
+    { return m_size; }
+
+    pair<double, double> range() const
+    { return make_pair(lower(0), upper(size() - 1)); }
+
+private:
+    SeriesType         m_series;
+    size_t             m_size;
+};
+
+
+template <typename SeriesType>
+class node_centered_axis
+{
+public:
+    node_centered_axis()
+        :   m_series(SeriesType()),
+            m_size(0)
+    {}
+
+    node_centered_axis(SeriesType series, size_t size)
+        :   m_series(series),
+            m_size(size)
+    {}
+
+    double operator()(size_t n) const
+    { return m_series(n); }
+
+    double lower(size_t n) const
+    { return m_series(n); }
+
+    double upper(size_t n) const
+    { return m_series(n); }
+
+    double width(size_t n) const
+    { return 0.0; }
+
+    size_t size() const
+    { return m_size; }
+
+    pair<double, double> range() const
+    { return make_pair(lower(0), upper(size() - 1)); }
+
+private:
+    SeriesType         m_series;
+    size_t             m_size;
+};
+
+} //# namespace BBS
+} //# namespace LOFAR
+
+#endif
diff --git a/CEP/BB/BBSKernel/include/BBSKernel/BBSKernelStructs.h b/CEP/BB/BBSKernel/include/BBSKernel/BBSKernelStructs.h
index adbf309bec04ac4a7de071487be2e0ea1964fae5..11298ef8c17e24011f039ca9734f650b222b76c8 100644
--- a/CEP/BB/BBSKernel/include/BBSKernel/BBSKernelStructs.h
+++ b/CEP/BB/BBSKernel/include/BBSKernel/BBSKernelStructs.h
@@ -26,9 +26,12 @@
 #include <Common/lofar_vector.h>
 #include <Common/lofar_string.h>
 #include <Common/lofar_iosfwd.h>
+#include <utility>
 
 namespace LOFAR
 {
+  using std::pair;
+
   //# Forward declarations
   class BlobIStream;
   class BlobOStream;
@@ -79,7 +82,7 @@ namespace LOFAR
       Baselines         baselines;
       Correlation       correlation;
       vector<string>    sources;
-      vector<string>    instrumentModel;    
+      vector<string>    instrumentModel;
     };
 
 
@@ -103,9 +106,9 @@ namespace LOFAR
 
     struct GenerateContext: Context
     {
-      vector<string>    unknowns;
-      vector<string>    excludedUnknowns;
-      vector<MeqDomain> solveDomains;
+      vector<string>        unknowns;
+      vector<string>        excludedUnknowns;
+      pair<size_t, size_t>  domainSize;
     };
 
     // I/O stream methods
diff --git a/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqJonesVisData.h b/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqJonesVisData.h
new file mode 100644
index 0000000000000000000000000000000000000000..8f4dadaddff22f6d15e1c4dd85d8d851728d4fd3
--- /dev/null
+++ b/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqJonesVisData.h
@@ -0,0 +1,56 @@
+//# MeqJonesVisData.h: 
+//#
+//# Copyright (C) 2007
+//# ASTRON (Netherlands Foundation for Research in Astronomy)
+//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//# This program 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 2 of the License, or
+//# (at your option) any later version.
+//#
+//# This program 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 this program; if not, write to the Free Software
+//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//# $Id$
+
+#ifndef MNS_MEQJONESVISDATA_H
+#define MNS_MEQJONESVISDATA_H
+
+#include <BBSKernel/MNS/MeqJonesExpr.h>
+#include <BBSKernel/VisData.h>
+
+namespace LOFAR
+{
+namespace BBS
+{
+
+class MeqJonesVisData: public MeqJonesExprRep
+{
+public:
+    MeqJonesVisData(VisData::Pointer vdata, baseline_t baseline);
+
+    ~MeqJonesVisData()
+    {}
+
+    // Get the result of the expression for the given domain.
+    virtual MeqJonesResult getJResult (const MeqRequest&);
+
+private:
+    void copy(double *re, double *im,
+        const boost::multi_array<sample_t, 4>::const_array_view<2>::type &src);
+
+    VisData::Pointer    itsVisData;
+    size_t              itsBaselineIndex;
+};
+
+} // namespace BBS
+} // namespace LOFAR
+
+#endif
diff --git a/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqParm.h b/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqParm.h
index 3d995cd917439fa11f6f34b0e4e7341e34699377..797634886b9fbab9dbeeeef02d1e6de8a50e80f6 100644
--- a/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqParm.h
+++ b/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqParm.h
@@ -99,6 +99,7 @@ public:
 
   // Make the new value persistent (for the given domain).
   virtual void save();
+  virtual void save(size_t domainIndex);
 
   // Functions needed for MeqParmFunklet.
   // By default they throw an exception.
@@ -160,6 +161,8 @@ public:
     { return itsParmPtr->getFunklets(); }
   void save()
     { itsParmPtr->save(); }
+  void save(size_t domainIndex)
+    { itsParmPtr->save(domainIndex); }
   void update (const ParmData& values)
     { itsParmPtr->update (values); }
   void update (const vector<double>& value)
diff --git a/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqParmFunklet.h b/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqParmFunklet.h
index b350a4589106091a695157e12b7a76b06f59f904..fc7ad17975d2d8a8e9ff62d2c69258c285f9f060 100644
--- a/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqParmFunklet.h
+++ b/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqParmFunklet.h
@@ -103,6 +103,7 @@ public:
 
   // Make the new value persistent (for the given domain).
   virtual void save();
+  virtual void save(size_t domainIndex);
 
   // Update the solvable parameter with the new value.
   virtual void update (const ParmData& values);
diff --git a/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqRequest.h b/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqRequest.h
index dcaa9b001c849af84e8ae682cf902b0cabb581c0..4cc2869aa9204d6ebe1ef2ff1ff02381081a3bd8 100644
--- a/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqRequest.h
+++ b/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqRequest.h
@@ -31,11 +31,13 @@
 #include <BBSKernel/MNS/MeqDomain.h>
 #include <BBSKernel/MNS/MeqMatrix.h>
 #include <Common/lofar_vector.h>
+#include <utility>
 
 namespace LOFAR
 {
 namespace BBS
 {
+using std::pair;
 
 // \ingroup BBSKernel
 // \addtogroup MNS
@@ -106,12 +108,18 @@ public:
 
   // Set or get the first X-value (i.e. first channel).
   // <group>
-  void setFirstX (int firstX)
-    { itsFirstX = firstX; }
-  int firstX() const
-    { return itsFirstX; }
+//  void setFirstX (int firstX)
+//    { itsFirstX = firstX; }
+//  int firstX() const
+//    { return itsFirstX; }
   // </group>
 
+  void setOffset(pair<size_t, size_t> offset)
+  { itsOffset = offset; }
+
+  pair<size_t, size_t> offset() const
+  { return itsOffset; }
+
   // Get the request id.
   MeqRequestId getId() const
     { return itsRequestId; }
@@ -128,9 +136,10 @@ private:
   double         itsStepX;
   vector<double> itsY;     //# The vector of Y values.
   double*        itsYP;    //# The pointer to itsY for a partial request
-  int            itsFirstX;
+//  int            itsFirstX;
   int            itsSourceNr;
   int            itsNspids;
+  pair<size_t, size_t>  itsOffset;
 
   static MeqRequestId theirRequestId;
 };
diff --git a/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqStatUVW.h b/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqStatUVW.h
index d3f533a175690e01221984a4c149ef0dc138b1bc..013c1c580bd14f6f016379cd480317837c84537c 100644
--- a/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqStatUVW.h
+++ b/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqStatUVW.h
@@ -56,7 +56,8 @@ public:
   MeqStatUVW() {};
 
 //#   MeqStatUVW (MeqStation*, const MeqPhaseRef*);
-  MeqStatUVW(MeqStation* station, const pair<double, double> &phaseCenter, const vector<double> &arrayPosition);
+  MeqStatUVW(MeqStation *station, const casa::MDirection &phaseCenter,
+    const casa::MPosition &arrayPosition);
 
   void calculate (const MeqRequest&);
 
diff --git a/CEP/BB/BBSKernel/include/BBSKernel/Makefile.am b/CEP/BB/BBSKernel/include/BBSKernel/Makefile.am
index 137226951b6e37108018aedd63acbbfc1de4923e..d74ded1e593429da5db2cc3fcd6528aa91b754c3 100644
--- a/CEP/BB/BBSKernel/include/BBSKernel/Makefile.am
+++ b/CEP/BB/BBSKernel/include/BBSKernel/Makefile.am
@@ -1,20 +1,16 @@
 pkginclude_MNSdir = $(pkgincludedir)/MNS
 
 pkginclude_HEADERS =		\
+	Axis.h			\
 	BBSKernelStructs.h	\
 	BBSStatus.h		\
 	Exceptions.h		\
-	FlagsMap.h		\
-	MMap.h			\
-	MMapMSInfo.h		\
-	ParmData.h		\
-	ParmWriter.h		\
+	Measurement.h		\
+	MeasurementAIPS.h	\
+	Model.h			\
 	Prediffer.h		\
-	Quality.h		\
-	SolveProp.h		\
-	Solver.h		\
-	StepProp.h		\
-	StrategyProp.h
+	VisData.h		\
+	VisSelection.h
 
 pkginclude_MNS_HEADERS	= 	\
 	MNS/MeqBaseDFTPS.h	\
@@ -29,12 +25,12 @@ pkginclude_MNS_HEADERS	= 	\
 	MNS/MeqJonesCMul3.h	\
 	MNS/MeqJonesExpr.h	\
 	MNS/MeqJonesInvert.h	\
-	MNS/MeqJonesMMap.h	\
 	MNS/MeqJonesMul2.h	\
 	MNS/MeqJonesMul3.h	\
 	MNS/MeqJonesNode.h	\
 	MNS/MeqJonesResult.h	\
 	MNS/MeqJonesSum.h	\
+	MNS/MeqJonesVisData.h	\
 	MNS/MeqLMN.h		\
 	MNS/MeqMatrixComplexArr.h \
 	MNS/MeqMatrixComplexSca.h \
diff --git a/CEP/BB/BBSKernel/include/BBSKernel/Measurement.h b/CEP/BB/BBSKernel/include/BBSKernel/Measurement.h
new file mode 100644
index 0000000000000000000000000000000000000000..19da4aa400c7ae5f9208e9d9cd80779f1cbed906
--- /dev/null
+++ b/CEP/BB/BBSKernel/include/BBSKernel/Measurement.h
@@ -0,0 +1,116 @@
+//# Measurement.h: Interface class for measurement I/O.
+//#
+//# Copyright (C) 2007
+//# ASTRON (Netherlands Foundation for Research in Astronomy)
+//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//# This program 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 2 of the License, or
+//# (at your option) any later version.
+//#
+//# This program 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 this program; if not, write to the Free Software
+//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//# $Id$
+
+#ifndef LOFAR_BBS_BBSKERNEL_MEASUREMENT_H
+#define LOFAR_BBS_BBSKERNEL_MEASUREMENT_H
+
+#include <BBSKernel/VisSelection.h>
+#include <BBSKernel/VisData.h>
+
+#include <Common/lofar_string.h>
+#include <Common/lofar_vector.h>
+#include <Common/lofar_set.h>
+#include <utility>
+
+#include <measures/Measures/MDirection.h>
+#include <measures/Measures/MEpoch.h>
+#include <measures/Measures/MPosition.h>
+
+namespace LOFAR
+{
+namespace BBS
+{
+
+struct Station
+{
+    string              name;
+    casa::MPosition     position;
+};
+
+class Instrument
+{
+public:
+    size_t getStationCount() const
+    { return stations.size(); }
+
+    string              name;
+    casa::MPosition     position;
+    vector<Station>     stations;
+    map<string, size_t> stationIndex;
+};
+
+class Measurement
+{
+public:
+    typedef shared_ptr<Measurement> Pointer;
+
+    virtual ~Measurement()
+    {
+    }
+
+    const Instrument &getInstrument() const
+    { return itsInstrument; }
+
+    const casa::MDirection &getPhaseCenter() const
+    { return itsPhaseCenter; }
+
+    const vector<string> &getCorrelations() const
+    { return itsCorrelationProducts; }
+
+    size_t getCorrelationCount() const
+    { return itsCorrelationProducts.size(); }
+
+    size_t getChannelCount() const
+    { return itsSpectrum.size(); }
+
+    const cell_centered_axis<regular_series> &getSpectrum() const
+    { return itsSpectrum; }
+
+    pair<double, double> getFreqRange() const
+    { return itsSpectrum.range(); }
+
+    pair<casa::MEpoch, casa::MEpoch> getTimeRange() const
+    { return itsTimeRange; }
+
+    virtual VisGrid grid(const VisSelection &selection) const = 0;
+
+    virtual VisData::Pointer read(const VisSelection &selection,
+        const string &column = "DATA",
+        bool readUVW = true) const = 0;
+
+    virtual void write(const VisSelection &selection,
+        VisData::Pointer buffer,
+        const string &column = "CORRECTED_DATA",
+        bool writeFlags = true) const = 0;
+
+protected:
+    Instrument                          itsInstrument;
+    casa::MDirection                    itsPhaseCenter;
+    pair<casa::MEpoch, casa::MEpoch>    itsTimeRange;
+    cell_centered_axis<regular_series>  itsSpectrum;
+    vector<string>                      itsCorrelationProducts;
+};
+
+} //# namespace BBS
+} //# namespace LOFAR
+
+#endif
diff --git a/CEP/BB/BBSKernel/include/BBSKernel/MeasurementAIPS.h b/CEP/BB/BBSKernel/include/BBSKernel/MeasurementAIPS.h
new file mode 100644
index 0000000000000000000000000000000000000000..ab1fcea7e1ecd33cee8ad6853602b1cc8a4ac5e4
--- /dev/null
+++ b/CEP/BB/BBSKernel/include/BBSKernel/MeasurementAIPS.h
@@ -0,0 +1,93 @@
+//# MeasurementAIPS.h: 
+//#
+//# Copyright (C) 2007
+//# ASTRON (Netherlands Foundation for Research in Astronomy)
+//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//# This program 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 2 of the License, or
+//# (at your option) any later version.
+//#
+//# This program 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 this program; if not, write to the Free Software
+//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//# $Id$
+
+#ifndef LOFAR_BBS_BBSKERNEL_MEASUREMENTAIPS_H
+#define LOFAR_BBS_BBSKERNEL_MEASUREMENTAIPS_H
+
+#include <BBSKernel/Measurement.h>
+#include <Common/LofarTypes.h>
+#include <Common/lofar_string.h>
+
+#include <casa/Arrays/Slicer.h>
+#include <ms/MeasurementSets/MeasurementSet.h>
+
+namespace LOFAR
+{
+namespace BBS
+{
+class VisSelection;
+
+class MeasurementAIPS: public Measurement
+{
+public:
+    MeasurementAIPS(string filename,
+        uint observationId = 0,
+        uint dataDescriptionId = 0,
+        uint fieldId = 0);
+
+    ~MeasurementAIPS();
+
+    virtual VisGrid grid(const VisSelection &selection) const;
+
+    virtual VisData::Pointer read(const VisSelection &selection,
+        const string &column = "DATA",
+        bool readUVW = true) const;
+
+    virtual void write(const VisSelection &selection,
+        VisData::Pointer buffer,
+        const string &column = "CORRECTED_DATA",
+        bool writeFlags = true) const;
+
+private:
+    Instrument readInstrumentInfo
+        (const casa::MSAntenna &tab_antenna,
+        const casa::MSObservation &tab_observation,
+        uint id);
+
+    vector<string> readPolarizationInfo
+        (const casa::MSPolarization &tab_polarization, uint id);
+
+    void readSpectralInfo
+        (const casa::MSSpectralWindow &tab_spectralWindow, uint id);
+
+    casa::MDirection readFieldInfo(const casa::MSField &tab_field, uint id);
+
+    casa::TableExprNode getTAQLExpression(const VisSelection &selection) const;
+
+    casa::Slicer getCellSlicer(const VisSelection &selection) const;
+
+    VisGrid getGrid(const casa::Table tab_selection, const casa::Slicer slicer)
+        const;
+
+    VisData::Pointer allocate(const VisGrid &grid) const;
+
+    string                  itsFilename;
+    casa::MeasurementSet    itsMS;
+
+    casa::Int               itsObservationId, itsDataDescriptionId,
+                            itsFieldId;
+};
+
+} //# namespace BBS
+} //# namespace LOFAR
+
+#endif
diff --git a/CEP/BB/BBSKernel/include/BBSKernel/Model.h b/CEP/BB/BBSKernel/include/BBSKernel/Model.h
new file mode 100644
index 0000000000000000000000000000000000000000..a9f2280e50206dd367b33ed07d763d005db7fccf
--- /dev/null
+++ b/CEP/BB/BBSKernel/include/BBSKernel/Model.h
@@ -0,0 +1,104 @@
+//# Model.h:
+//#
+//# Copyright (C) 2007
+//# ASTRON (Netherlands Foundation for Research in Astronomy)
+//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//# This program 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 2 of the License, or
+//# (at your option) any later version.
+//#
+//# This program 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 this program; if not, write to the Free Software
+//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//# $Id$
+
+
+#ifndef LOFAR_BBS_BBSKERNEL_MODEL_H
+#define LOFAR_BBS_BBSKERNEL_MODEL_H
+
+#include <Common/lofar_smartptr.h>
+#include <Common/lofar_vector.h>
+#include <Common/lofar_string.h>
+#include <Common/lofar_map.h>
+#include <Common/lofar_set.h>
+
+#include <BBSKernel/VisData.h>
+#include <BBSKernel/MNS/MeqJonesResult.h>
+#include <BBSKernel/MNS/MeqSourceList.h>
+
+#include <ParmDB/ParmDB.h>
+
+
+namespace LOFAR
+{
+namespace BBS
+{
+class Instrument;
+class MeqParmGroup;
+class MeqPhaseRef;
+class MeqRequest;
+class MeqStation;
+class MeqStatUVW;
+class MeqLMN;
+class MeqJonesExpr;
+
+class Model
+{
+public:
+    typedef shared_ptr<Model> Pointer;
+
+    enum ModelComponent
+    {
+        GAIN = 0,
+        DIRECTIONAL_GAIN,
+        BANDPASS,
+        PHASORS,
+        N_ModelComponent
+    };
+
+    enum EquationType
+    {
+        PREDICT = 0,
+        CORRECT,
+        N_EquationType
+    };
+
+    Model(const Instrument &instrument, MeqParmGroup &parmGroup,
+        ParmDB::ParmDB *skyDBase, MeqPhaseRef *phaseRef);
+
+    void setStationUVW(const Instrument &instrument, VisData::Pointer data);
+
+    void makeEquations(EquationType type, const vector<string> &components,
+        const set<baseline_t> &baselines, const vector<string> &sources,
+        MeqParmGroup &parmGroup, ParmDB::ParmDB *instrumentDBase,
+        MeqPhaseRef *phaseRef, VisData::Pointer data);
+
+    void precalculate(const MeqRequest& request);
+    MeqJonesResult evaluate(baseline_t baseline, const MeqRequest& request);
+
+private:
+    void makeStationNodes(const Instrument &instrument,
+        const MeqPhaseRef &phaseRef);
+
+    void makeSourceNodes(const vector<string> &names, MeqPhaseRef *phaseRef);
+
+    scoped_ptr<MeqSourceList>           itsSourceList;
+    vector<shared_ptr<MeqStation> >     itsStationNodes;
+    vector<shared_ptr<MeqStatUVW> >     itsUVWNodes;
+    vector<MeqSource*>                  itsSourceNodes;
+    vector<MeqLMN*>                     itsLMNNodes;
+    map<baseline_t, MeqJonesExpr>       itsEquations;
+};
+
+} //# namespace BBS
+} //# namespace LOFAR
+
+#endif
diff --git a/CEP/BB/BBSKernel/include/BBSKernel/Prediffer.h b/CEP/BB/BBSKernel/include/BBSKernel/Prediffer.h
index 45d5ed5255ea3567bece41751bdb83f459c24cc0..865fd117652652f7124d89c3976be19be792dda6 100644
--- a/CEP/BB/BBSKernel/include/BBSKernel/Prediffer.h
+++ b/CEP/BB/BBSKernel/include/BBSKernel/Prediffer.h
@@ -26,60 +26,45 @@
 // \file
 // Read and predict read visibilities
 
-#include <casa/BasicSL/Complex.h>
-#include <casa/Arrays/Matrix.h>
-#include <scimath/Fitting/LSQFit.h>
+//#include <casa/BasicSL/Complex.h>
+//#include <casa/Arrays/Matrix.h>
+
+#include <BBSKernel/Measurement.h>
+#include <BBSKernel/Model.h>
+#include <BBSKernel/VisSelection.h>
+#include <BBSKernel/VisData.h>
 
 #include <BBSKernel/BBSKernelStructs.h>
-#include <BBSKernel/StrategyProp.h>
-#include <BBSKernel/StepProp.h>
-#include <BBSKernel/SolveProp.h>
-#include <BBSKernel/ParmData.h>
-#include <BBSKernel/MMapMSInfo.h>
+//#include <BBSKernel/ParmData.h>
 #include <BBSKernel/MNS/MeqDomain.h>
 #include <BBSKernel/MNS/MeqJonesExpr.h>
-#include <BBSKernel/MNS/MeqJonesNode.h>
 #include <BBSKernel/MNS/MeqMatrix.h>
 #include <BBSKernel/MNS/MeqParm.h>
 #include <BBSKernel/MNS/MeqPhaseRef.h>
-#include <BBSKernel/MNS/MeqSourceList.h>
 #include <BBSKernel/MNS/MeqRequest.h>
-#include <BBSKernel/MNS/MeqStation.h>
-#include <BBSKernel/MNS/MeqStatUVW.h>
-#include <BBSKernel/MNS/MeqLMN.h>
-#include <BBSKernel/MNS/MeqDFTPS.h>
 #include <ParmDB/ParmDB.h>
 #include <ParmDB/ParmValue.h>
 #include <ParmDB/ParmDomain.h>
-#include <MS/MSDesc.h>
 
 #include <Common/Timer.h>
-#include <Common/LofarTypes.h>
 #include <Common/lofar_string.h>
 #include <Common/lofar_vector.h>
-#include <Common/lofar_iomanip.h>
+#include <Common/lofar_map.h>
 
-#include <map>
 #include <utility>
 
-namespace casa {
-  class Table;
+namespace casa
+{
+    class LSQFit;
 }
 
 namespace LOFAR
 {
 namespace BBS
 {
-
 // \addtogroup BBSKernel
 // @{
 
-//# Forward Declarations
-class MMap;
-class FlagsMap;
-class MeqJonesMMap;
-
-
 // Prediffer calculates the equations for the solver.
 // It reads the measured data and predicts the data from the model.
 // It subtracts them from each other and calculates the derivatives.
@@ -92,444 +77,207 @@ struct SolveDomainDescriptor
     vector<size_t>      unknownIndex;
     vector<double>      unknowns;
 };
-  
+
+
+struct ProcessingContext
+{
+    ProcessingContext()
+        :   derivativeCount(0),
+            domainSize(0, 0),
+            domainCount(0, 0)
+    {}
+
+    set<baseline_t>                 baselines;
+    set<pair<size_t, size_t> >      polarizations;
+
+    // Sum of the maximal number (over all solve domains) of partial derivatives
+    // of each parameter.
+    size_t                          derivativeCount;
+
+    // Nominal solve domain size along each axis in #channels, #timeslots.
+    std::pair<size_t, size_t>       domainSize;
+    // Number of solve domains along each axis (frequency, time).
+    std::pair<size_t, size_t>       domainCount;
+    vector<SolveDomainDescriptor>   domains;
+};
+
 
 class Prediffer
 {
 public:
-  // NOTE: new constructor to comply with BBSStep interface.
-  Prediffer(const string &measurementSet,
-            const string &inputColumn,
-            const string &skyParameterDB,
-            const string &instrumentParameterDB,
-            const string &historyDB,
-            uint subbandID,
-            bool calcUVW);
-                          
-  // Destructor
-  ~Prediffer();
-
-  // Lock and unlock the parm database tables.
-  // The user does not need to lock/unlock, but it can increase performance
-  // if many small accesses have to be done.
-  // <group>
-  void lock (bool lockForWrite = true)
-    { itsMEP->lock (lockForWrite); itsGSMMEP->lock (lockForWrite); }
-  void unlock()
-    { itsMEP->unlock(); itsGSMMEP->unlock(); }
-
-  bool setSelection(const vector<string> &stations, const Correlation &correlation);
-  
-  // Set the work domain.
-  // The work domain (in frequency and time) is adjusted to the
-  // observation domain of the MS used.
-  // It reads all parms in the given domain.
-  // It returns false if the given work domain has no overlap with the
-  // MS part handled by this Prediffer
-  // <group>
-  bool setWorkDomain(const MeqDomain& domain);
-  bool setWorkDomain(double startFreq, double endFreq, double startTime, double endTime);
-  bool setWorkDomain(int startChan, int endChan, double startTime, double lengthTime);
-  // </group>
-  
-  bool setContext(const PredictContext &context);
-  bool setContext(const SubtractContext &context);
-  bool setContext(const CorrectContext &context);
-  bool setContext(const GenerateContext &context);
-  
-  void predictVisibilities();
-  void subtractVisibilities();
-  void correctVisibilities();
-  void generateEquations(vector<casa::LSQFit> &equations);
-
-  
-  // Get the actual work domain for this MS (after a setStrategy).
-  const MeqDomain &getWorkDomain() const
-    { return itsWorkDomain; }
-
-  // Get the local data domain.
-  MeqDomain getLocalDataDomain() const;
-
-  // Return the solvable parms.
-  // The parms are in ascending order of spidnr.
-  const ParmDataInfo& getSolvableParmData() const
-    { return itsParmData; }
-
-  // There are three ways to update the solvable parms after the solver
-  // found a new solution.
-  // <group>
-  // Update the values of solvable parms.
-  // Using its spid index each parm takes its values from the vector.
-  void updateSolvableParms (const vector<double>& values);
-
-  // Update the given values (for the current domain) of solvable parms
-  // matching the corresponding parm name in the vector.
-  // Vector values with a name matching no solvable parm are ignored.
-  void updateSolvableParms (const ParmDataInfo& parmData);
-
-  // Update the solvable parm values (reread from table).
-  void updateSolvableParms();
-
-  void updateSolvableParms(size_t solveDomainIndex,
-    const vector<double> unknowns);
-
-  // Log the updated values of a single solve domain.
-  void logIteration(
-    const string &stepName,
-    size_t solveDomainIndex,
-    double rank,
-    double chiSquared,
-    double LMFactor);
-  
-  // Write the solved parms.
-  void writeParms();
+    Prediffer(const string &measurement, size_t subband,
+        const string &inputColumn,
+        const string &skyDBase, const string &instrumentDBase,
+        const string &historyDBase, bool readUVW);
+
+    // Destructor
+    ~Prediffer();
+
+    // Lock and unlock the parm database tables.
+    // The user does not need to lock/unlock, but it can increase performance
+    // if many small accesses have to be done.
+    // <group>
+    void lock(bool lockForWrite = true)
+    {
+        itsInstrumentDBase->lock(lockForWrite);
+        itsSkyDBase->lock(lockForWrite);
+    }
+
+    void unlock()
+    {
+        itsInstrumentDBase->unlock();
+        itsSkyDBase->unlock();
+    }
+
+    void setSelection(VisSelection selection);
+    void setChunkSize(size_t time);
+    bool nextChunk();
+
+    bool setContext(const PredictContext &context);
+    bool setContext(const SubtractContext &context);
+    bool setContext(const CorrectContext &context);
+    bool setContext(const GenerateContext &context);
+
+    void predict();
+    void subtract();
+    void correct();
+    void generate(pair<size_t, size_t> start, pair<size_t, size_t> end,
+        vector<casa::LSQFit> &solvers);
+
+    // Get the actual work domain for this MS (after a setStrategy).
+    const MeqDomain &getWorkDomain() const
+        { return itsWorkDomain; }
+
+    // Get the local data domain.
+    MeqDomain getLocalDataDomain() const;
+
+    // There are three ways to update the solvable parms after the solver
+    // found a new solution.
+    // <group>
+    // Update the values of solvable parms.
+    // Using its spid index each parm takes its values from the vector.
+    void updateSolvableParms (const vector<double>& values);
+
+    // Update the given values (for the current domain) of solvable parms
+    // matching the corresponding parm name in the vector.
+    // Vector values with a name matching no solvable parm are ignored.
+//    void updateSolvableParms (const ParmDataInfo& parmData);
+
+    // Update the solvable parm values (reread from table).
+    void updateSolvableParms();
+
+    void updateSolvableParms(size_t solveDomainIndex,
+        const vector<double> unknowns);
+
+    // Log the updated values of a single solve domain.
+    void logIteration(const string &stepName, size_t solveDomainIndex,
+        double rank, double chiSquared, double LMFactor);
+
+    // Write the solved parms.
+    void writeParms();
+    void writeParms(size_t solveDomainIndex);
+
+    const vector<SolveDomainDescriptor> &getSolveDomainDescriptors() const
+    {
+        return itsContext.domains;
+    }
 
 #ifdef EXPR_GRAPH
-  void writeExpressionGraph(const string &fileName, int baselineIndex);
+    void writeExpressionGraph(const string &fileName, baseline_t baseline);
 #endif
 
-  // Show the settings of the Prediffer.
-  void showSettings() const;
-
-  // Get the results instead of the equations.
-  // This is mainly used for test purposes.
-  vector<MeqResult> getResults (bool calcDeriv=true);
-
-  // Get the data and flags for the time domain.
-  // This is mainly used for test purposes.
-  void getData (bool useTree,
-        casa::Array<casa::Complex>& data,
-        casa::Array<casa::Bool>& flags);
-
-  const vector<SolveDomainDescriptor> &getSolveDomainDescriptors() const
-  {
-    return itsSolveDomainDescriptors;
-  }
-  
-  // DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED
-  // DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED
-  
-  // WARNING: DEPRECATED. Create Prediffer object for a specific
-  // MeaurementSet, MEQ model (with associated MEP database) and skymodel
-  // for the specified data descriptor (i.e. spectral window).
-  // The UVW coordinates can be calculated or taken from the MS.
-  Prediffer (const string& msName,
-         const LOFAR::ParmDB::ParmDBMeta& meqPtd,
-         const LOFAR::ParmDB::ParmDBMeta& skyPtd,
-         uint ddid,
-         bool calcUVW);
-  
-  // WARNING: DEPRECATED. Will be removed in the next release.
-  // Old interface to set strategy and steps.
-  // Set the strategy properties.
-  // It returns false if no antennas are to be used in this MS part.
-  bool setStrategyProp (const StrategyProp&);
-
-  // Set the properties to be used in the step that will be performed.
-  // It selects the data to be used and it builds the expression tree using
-  // the given instrument and source model.
-  // It returns false if the selection is such that no data is left.
-  bool setStepProp (const StepProp&);
-  
-  // Initialize all solvable parameters in the MeqExpr tree for the
-  // given solve domains.
-  // It sets the scids of the solvable parms and fills itsParmData.
-  // It returns false if no solvable parameters are found for this MS.
-  bool setSolveProp (const SolveProp&);
-  
-  // Get the equations for all selected baselines and fill the
-  // fitter vector with them.
-  // The fitter vector is resized as needed.
-  // All fitter objects are initialized before being filled.
-  void fillFitters(vector<casa::LSQFit>& fitters);
-
-  // Shift data to another phase reference position.
-  void shiftData();
-
-  // Apply corrections to the data.
-  void correctData();
-
-  // Subtract (corrupted) sources from the data.
-  void subtractData();
-
-  // Write the predicted data into the .res or .dat file.
-  void writePredictedData();
-
-  // DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED
-  // DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED
-
 private:
-  // Copy constructor and assignment are not allowed.
-  // <group>
-  Prediffer (const Prediffer& other);
-  Prediffer& operator= (const Prediffer& other);
-  // </group>
-
-  // Read measurement set meta data.
-  void readMeasurementSetMetaData(const string& fileName);
-
-  // Get the name of the file that contains the data that belongs to the specified column.
-  string getFileForColumn(const string &column);
-  
-  // Process the MS description for the given dd (spectral window).
-  void processMSDesc (uint ddid);
-
-  // Get the phase reference position of the first field.
-  void getPhaseRef (double ra, double dec, double startTime);
-
-  bool setContext(const Context &context);
-  void updateCorrelationMask(vector<bool> &mask, const vector<string> &requestedCorrelations);
-
-  // Get the station info (position and name).
-  void fillStations();
-
-  // Fill all UVW coordinates if they are not calculated.
-  void fillUVW();
-
-  // Get all sources from the sky model table.
-  // Also check the source groups.
-  void getSources();
-
-  // Make the entire tree.
-  void makeTree (const vector<string>& modelType,
-         const vector<string>& sourceNames);
-
-  // Create the expressions for each baseline and source(group).
-  // The gains can be expressed as real/imag or ampl/phase.
-  // The station parameters are optionally taken into account.
-  void makeLOFARExprs (const vector<MeqSource*>& sources,
-               const map<string, vector<int> >& groups,
-               bool useTotalGain, bool usePatchGain,
-               bool asAP,
-               bool useDipole, bool useBandpass);
-
-  // Find all nodes to be precalculated.
-  void setPrecalcNodes (vector<MeqJonesExpr>& nodes);
-
-  // Fill the fitter with the equations for the given baseline.
-  void fillEquation (int threadnr, void* arg,
-             const fcomplex* dataIn, fcomplex* dummy,
-             const bool* flags,
-             const MeqRequest& request, int blindex,
-             bool showd=false);
-
-  // Reset the loop variables for the getEquations loop.
-  void resetEqLoop();
-
-  // Map the correct data files (if not mapped yet).
-  // If a string is empty, the file is not mapped.
-  void mapDataFiles (const string& inFile, const string& outFile);
-
-  // Add a data column to the table and create a symlink for it.
-//  void addDataColumn (casa::Table& tab, const string& columnName,
-//              const string& symlinkName);
-  void addDataColumn (casa::Table& tab, const string& columnName);
-
-  // Define the signature of a function processing a baseline.
-  typedef void (Prediffer::*ProcessFuncBL) (int threadnr, void* arg,
-                        const fcomplex* dataIn,
-                        fcomplex* dataOut,
-                        const bool* flags,
-                        const MeqRequest& request,
-                        int blindex, bool showd);
-
-  // Loop through all data and process each baseline by ProcessFuncBL.
-  void processData (bool useFlags, bool preCalc, bool calcDeriv,
-            ProcessFuncBL func, void* arg);
-
-  // Subtract the data of a baseline.
-  void subtractBL (int threadnr, void* arg,
-           const fcomplex* dataIn, fcomplex* dataOut,
-           const bool* flags,
-           const MeqRequest& request, int blindex,
-           bool showd);
-
-  // Correct the data of a baseline.
-  void correctBL (int threadnr, void* arg,
-          const fcomplex* dataIn, fcomplex* dataOut,
-          const bool* flags,
-          const MeqRequest& request, int blindex,
-          bool showd);
-
-  // Write the predicted data of a baseline.
-  void predictBL (int threadnr, void* arg,
-          const fcomplex* dummy, fcomplex* dataOut,
-          const bool* flags,
-          const MeqRequest& request, int blindex,
-          bool showd);
-
-  // Get the data of a single baseline.
-  // <group>
-  void getBL (int threadnr, void* arg,
-          const fcomplex* data, fcomplex*,
-          const bool* flags,
-          const MeqRequest&, int blindex,
-          bool);
-  void getMapBL (int threadnr, void* arg,
-         const fcomplex* data, fcomplex*,
-         const bool* flags,
-         const MeqRequest& request, int blindex,
-         bool);
-  // </group>
-
-  // Make all parameters non-solvable.
-  void clearSolvableParms();
-
-  // Read the polcs for all parameters for the current work domain.
-  void readParms();
-
-  // Get access to the next data chunk and fill in all pointers.
-  // The data pointers are filled in the MMapMSInfo object.
-  bool nextDataChunk (bool useFitters);
-
-  // Do the precalculations for all lower level nodes.
-  void precalcNodes (const MeqRequest& request);
-
-  // Show the data on cout.
-  void showData (int corr, int sdch, int inc, int nrchan,
-         const bool* flags, const fcomplex* data,
-         const double* realData, const double* imagData);
-
-  // DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED
-  // DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED
-  
-  // Initialize all solvable parameters in the MeqExpr tree for the
-  // given solve domains.
-  // It sets the scids of the solvable parms and fills itsParmData.
-  void initSolvableParms (const vector<MeqDomain>& solveDomains);
-
-  // Get measurement set description from file
-  // NB. DEPRECATED -- only use for debugging purposes, will
-  // be removed in the next release.
-  void readDescriptiveData (const string& fileName);
-
-  // Select the stations for a strategy.
-  // False is returned if no stations/baselines are left.
-  bool selectStations (const vector<int>& antnrs, bool useAutoCorr);
-
-  // Do the selection of baselines and correlations for a step.
-  bool selectStep (const vector<int>& ant1,
-           const vector<int>& ant2,
-           bool useAutoCorrelations,
-           const vector<bool>& corr);
-
-  // Fill indices and count nr of baselines and correlations selected.
-  bool fillBaseCorr (const casa::Matrix<bool>& blSel);
-
-  // DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED
-  // DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED
-  
-  uint                  itsSubbandID;
-  bool                  itsCalcUVW;
-  
-  string                itsMSName;      //# Measurement set name
-  LOFAR::ParmDB::ParmDB *itsMEP;        //# Common parmtable
-  string                itsMEPName;     //# Common parmtable name
-  LOFAR::ParmDB::ParmDB *itsGSMMEP;     //# parmtable for GSM parameters
-  string                itsGSMMEPName;  //# GSM parameters parmtable name
-  LOFAR::ParmDB::ParmDB *itsHistoryDB;  //# parmtable for solve history
-  MeqParmGroup          itsParmGroup;   //# container for all parms
-
-  MeqPhaseRef           itsPhaseRef;    //# Phase reference position in J2000
-
-  MeqSourceList*        itsSources;
-  vector<MeqExpr>       itsLMN;         //# LMN for sources used
-  vector<MeqStation*>   itsStations;    //# All stations
-  vector<MeqStation*>   itsSelStations; //# Subset of selected stations
-  vector<MeqStatUVW*>   itsStatUVW;     //# UVW values per station
-  vector<MeqJonesExpr>  itsExpr;        //# solve expression tree per baseline
-  vector<vector<MeqExprRep*> > itsPrecalcNodes;  //# nodes to be precalculated
-  vector<MeqJonesExpr>  itsCorrStat;    //# Correct per station
-  vector<MeqJonesMMap*> itsCorrMMap;    //# MMap for each baseline
-  vector<MeqJonesExpr>  itsCorrExpr;    //# Ampl/phase expressions (to correct)
-
-  string itsInDataColumn;
-  string itsOutDataColumn;
-
-  MSDesc itsMSDesc;                   //# description of the MS
-  map<string, string>  itsColumns;   //# mapping from column name to table file within MS.
-  double itsStartFreq;                //# start frequency of observation
-  double itsEndFreq;
-  double itsStepFreq;
-  int    itsNrChan;                   //# nr of channels in observation
-  int    itsFirstChan;                //# first channel of selected domain
-  int    itsLastChan;                 //# last channel of selected domain
-  bool   itsReverseChan;              //# Channels are in reversed order
-  int    itsDataFirstChan;            //# First channel to use in data
-                                      //# (can be different if reversed order)
-
-  MeqDomain    itsWorkDomain;         //# Current work domain
-  vector<int>  itsNrScids;            //# Nr of solvable coeff per solve domain
-  int          itsNrPert;             //# Nr of perturbed values in result
-  ParmDataInfo itsParmData;           //# solvable parm info.
-
-  vector<bool>         itsSelectedCorr;//# Correlations selected in initial data selection (setSelection())
-  vector<bool>         itsCorr;        //# Correlations to use (subset of itsSelectedCorr)
-  int                  itsNCorr;       //# Number of correlations (XX, etc.)
-  int                  itsNSelCorr;    //# Number of correlations selected
-  casa::Vector<double> itsTimes;       //# All times in MS
-  casa::Vector<double> itsIntervals;   //# All intervals in MS
-
-  //# All baselines in the MS are numbered 0 to itsNrBl-1.
-  unsigned int         itsNrBl;        //# Total number of baselines in MS
-  //# Define the baselines that can be used (thus selected in strategy).
-  //# The seqnr is the sequence number of the baseline in the MS.
-  
-  map<pair<int, int>, int>    itsSelectedBaselines;
-  
-  //# Define which baselines are selected in the select function.
-  vector<int>    itsBLInx;         //# Seqnrs of selected baselines
-  unsigned int   itsTimeIndex;     //# The index of the current time
-  unsigned int   itsNrTimes;       //# The number of times in the time domain
-  unsigned int   itsNrTimesDone;   //# Nr of times done after a setDomain
-  vector<double> itsChunkTimes;    //# Times in current data chunk
-
-  MMapMSInfo     itsMSMapInfo;     //# Info about mapped input and output file
-  MMap*          itsInDataMap;     //# Input data file mapped
-  MMap*          itsOutDataMap;    //# Output data file mapped (can same as in)
-  FlagsMap*      itsFlagsMap;      //# Flags file mapped
-  MMap*          itsWeightMap;     //# Weights file mapped
-  bool           itsIsWeightSpec;  //# true = weight per channel
-
-  //# All parm values in current work domain.
-  map<string,LOFAR::ParmDB::ParmValueSet> itsParmValues;
-
-  //# Fitter info set by initSolvableParms.
-  vector<int> itsFreqFitInx;       //# Fitter for each freq in work domain
-                                   //# for the data in the MS resolution
-  vector<int> itsTimeFitInx;       //# Fitter for each time in work domain
-  uint        itsFreqNrFit;        //# Nr of fitters in freq direction
-
-  //# Thread private buffers.
-  int itsNthread;
-  vector<casa::Block<bool> >      itsFlagVecs;
-  vector<vector<const double*> >  itsResultVecs;
-  vector<vector<double> >         itsDiffVecs;
-  vector<vector<uint> >           itsIndexVecs;
-  //  vector<casa::Block<bool> >     itsOrdFlagVecs;
-
-  //# Timers.
-  NSTimer itsPredTimer;
-  NSTimer itsEqTimer;
-  
-  vector<MeqDomain>               itsSolveDomains;
-  
-  vector<SolveDomainDescriptor>   itsSolveDomainDescriptors;
-
-  void initializeSolveDomains(const vector<MeqDomain> &globalSolveDomains);
-
-#ifdef COMPUTE_SQUARED_ERROR  
-  vector<double> itsSquaredErrorReal;
-  vector<double> itsSquaredErrorImag;
-#endif 
-       
-  // DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED
-  // DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED
-  
-  casa::Matrix<bool>   itsBLSel;       //# Antenna pair selected in strategy?
-  
-  // DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED
-  // DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED
+    // Copy constructor and assignment are not allowed.
+    // <group>
+    Prediffer (const Prediffer& other);
+    Prediffer& operator= (const Prediffer& other);
+    // </group>
+
+    bool setContext(const Context &context);
+
+    void initializeSolveDomains(std::pair<size_t, size_t> size);
+
+    // Make all parameters non-solvable.
+    void clearSolvableParms();
+
+    // Read the polcs for all parameters for the current work domain.
+    void readParms();
+
+    // Define the signature of a function processing a baseline.
+    typedef void (Prediffer::*BaselineProcessor) (int threadnr, void* arguments,
+        VisData::Pointer chunk, pair<size_t, size_t> offset,
+        const MeqRequest& request, baseline_t baseline, bool showd);
+
+    // Loop through all data and process each baseline by ProcessFuncBL.
+    void process(bool useFlags, bool precalc, bool derivatives,
+        pair<size_t, size_t> start, pair<size_t, size_t> end,
+        BaselineProcessor processor, void *arguments);
+
+    // Write the predicted data of a baseline.
+    void predictBaseline(int threadnr, void* arguments, VisData::Pointer chunk,
+        pair<size_t, size_t> offset, const MeqRequest& request,
+        baseline_t baseline, bool showd = false);
+
+    // Subtract the data of a baseline.
+    void subtractBaseline(int threadnr, void* arguments, VisData::Pointer chunk,
+        pair<size_t, size_t> offset, const MeqRequest& request,
+        baseline_t baseline, bool showd = false);
+
+    // Correct the data of a baseline.
+    void correctBaseline(int threadnr, void* arguments, VisData::Pointer chunk,
+        pair<size_t, size_t> offset, const MeqRequest& request,
+        baseline_t baseline, bool showd = false);
+
+    // Generate equations for a baseline.
+    void generateBaseline(int threadnr, void* arguments, VisData::Pointer chunk,
+        pair<size_t, size_t> offset, const MeqRequest& request,
+        baseline_t baseline, bool showd = false);
+
+    void testFlagsBaseline(int threadnr, void* arguments,
+        VisData::Pointer chunk, const MeqRequest& request, baseline_t baseline,
+        bool showd);
+
+
+    size_t                              itsSubband;
+    string                              itsInputColumn;
+    string                              itsOutputColumn;
+    bool                                itsReadUVW;
+
+    scoped_ptr<ParmDB::ParmDB>          itsInstrumentDBase;
+    scoped_ptr<ParmDB::ParmDB>          itsSkyDBase;
+    scoped_ptr<ParmDB::ParmDB>          itsHistoryDBase;
+
+    //# Container for all parameters.
+    MeqParmGroup                        itsParmGroup;
+    //# Phase reference position in J2000 coordinates.
+    MeqPhaseRef                         itsPhaseRef;
+
+    MeqDomain                           itsWorkDomain;
+
+    //# All parm values in current work domain.
+    map<string,ParmDB::ParmValueSet>    itsParmValues;
+
+    //# Thread private buffers.
+    int itsNthread;
+    vector<casa::Block<bool> >          itsFlagVecs;
+    vector<vector<const double*> >      itsResultVecs;
+    vector<vector<double> >             itsDiffVecs;
+    vector<vector<uint> >               itsIndexVecs;
+
+    NSTimer                             itsPredTimer, itsEqTimer;
+
+    Measurement::Pointer                itsMeasurement;
+    Model::Pointer                      itsModel;
+    VisGrid                             itsGrid;
+    VisSelection                        itsChunkSelection;
+    VisData::Pointer                    itsChunkData;
+    size_t                              itsChunkSize, itsChunkPosition;
+    ProcessingContext                   itsContext;
+
+#ifdef COMPUTE_SQUARED_ERROR
+    vector<double>                      itsSquaredErrorReal;
+    vector<double>                      itsSquaredErrorImag;
+#endif
 };
 
 // @}
diff --git a/CEP/BB/BBSKernel/include/BBSKernel/VisData.h b/CEP/BB/BBSKernel/include/BBSKernel/VisData.h
new file mode 100644
index 0000000000000000000000000000000000000000..4a76c8570cf49bcc6be75a117398ad535ed4deda
--- /dev/null
+++ b/CEP/BB/BBSKernel/include/BBSKernel/VisData.h
@@ -0,0 +1,109 @@
+//# VisData.h: 
+//#
+//# Copyright (C) 2007
+//# ASTRON (Netherlands Foundation for Research in Astronomy)
+//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//# This program 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 2 of the License, or
+//# (at your option) any later version.
+//#
+//# This program 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 this program; if not, write to the Free Software
+//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//# $Id$
+
+#ifndef LOFAR_BBS_BBSKERNEL_VISDATA_H
+#define LOFAR_BBS_BBSKERNEL_VISDATA_H
+
+#include <Common/LofarTypes.h>
+#include <Common/lofar_smartptr.h>
+#include <Common/lofar_map.h>
+#include <Common/lofar_set.h>
+#include <Common/lofar_string.h>
+
+#include <BBSKernel/Axis.h>
+
+#include <boost/multi_array.hpp>
+#include <utility>
+
+namespace LOFAR
+{
+namespace BBS
+{
+using std::pair;
+
+typedef fcomplex                sample_t;
+typedef bool                    flag_t;
+typedef uint8                   tslot_flag_t;
+typedef pair<uint32, uint32>    baseline_t;
+
+// TODO: Find an elegant way to unify VisGrid and VisData.
+
+class VisGrid
+{
+public:
+    cell_centered_axis<regular_series>      freq;
+    cell_centered_axis<irregular_series>    time;
+    set<baseline_t>                         baselines;
+    set<string>                             polarizations;
+};
+
+
+class VisData
+{
+public:
+    typedef shared_ptr<VisData>         Pointer;
+
+    enum TimeslotFlag
+    {
+        UNAVAILABLE         = 1<<1,
+        FLAGGED_IN_INPUT    = 1<<2,
+        N_TimeslotFlag
+    };
+
+    VisData(uint32 nTimeslots,
+        uint32 nBaselines,
+        uint32 nChannels,
+        uint32 nPolarizations);
+
+    size_t getPolarizationCount() const
+    { return polarizations.size(); }
+
+    size_t getChannelCount() const
+    { return freq.size(); }
+
+    size_t getTimeslotCount() const
+    { return time.size(); }
+
+    size_t getBaselineCount() const
+    { return baselines.size(); }
+
+    bool hasBaseline(baseline_t baseline) const;
+    size_t getBaselineIndex(baseline_t baseline) const;
+
+    bool hasPolarization(const string &polarization) const;
+    size_t getPolarizationIndex(const string &polarization) const;
+
+    cell_centered_axis<regular_series>      freq;
+    cell_centered_axis<irregular_series>    time;
+    map<baseline_t, size_t>                 baselines;
+    map<string, size_t>                     polarizations;
+
+    boost::multi_array<double, 3>           uvw;
+    boost::multi_array<tslot_flag_t, 2>     tslot_flag;
+    boost::multi_array<flag_t, 4>           vis_flag;
+    boost::multi_array<sample_t, 4>         vis_data;
+};
+
+} //# namespace BBS
+} //# namespace LOFAR
+
+#endif
diff --git a/CEP/BB/BBSKernel/include/BBSKernel/VisSelection.h b/CEP/BB/BBSKernel/include/BBSKernel/VisSelection.h
new file mode 100644
index 0000000000000000000000000000000000000000..1165b004d4ee253a02a922fddea40a886fdbe098
--- /dev/null
+++ b/CEP/BB/BBSKernel/include/BBSKernel/VisSelection.h
@@ -0,0 +1,119 @@
+//# VisSelection.h: 
+//#
+//# Copyright (C) 2007
+//# ASTRON (Netherlands Foundation for Research in Astronomy)
+//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//# This program 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 2 of the License, or
+//# (at your option) any later version.
+//#
+//# This program 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 this program; if not, write to the Free Software
+//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//# $Id$
+
+#ifndef LOFAR_BBS_BBSKERNEL_VISSELECTION_H
+#define LOFAR_BBS_BBSKERNEL_VISSELECTION_H
+
+#include <Common/LofarTypes.h>
+#include <Common/LofarLogger.h>
+#include <Common/lofar_set.h>
+#include <Common/lofar_vector.h>
+#include <Common/lofar_string.h>
+
+#include <utility>
+
+namespace LOFAR
+{
+namespace BBS
+{
+using std::pair;
+
+class VisSelection
+{
+public:
+    enum FieldEnum
+    {
+//        FREQ_START = 0,
+//        FREQ_END,
+        CHANNEL_START = 0,
+        CHANNEL_END,
+//        CHANNEL_STEP,
+        TIME_START,
+        TIME_END,
+        STATIONS,
+        CORRELATIONS,
+        BASELINE_FILTER,
+        N_FieldEnum
+    };
+
+    enum BaselineFilter
+    {
+        AUTO = 0,
+        CROSS,
+        N_BaselineFilter
+    };
+
+    VisSelection();
+
+    void clear(FieldEnum field)
+    { itsFieldFlags[field] = false; }
+
+    bool isSet(FieldEnum field) const
+    { return itsFieldFlags[field]; }
+
+    void setChannelRange(size_t start, size_t end);
+    void setTimeRange(string start, string end);
+    void setTimeRange(double start, double end);
+    void setCorrelations(vector<string> correlations);
+    void setStations(vector<string> stations);
+    void setBaselineFilter(BaselineFilter filter);
+
+    pair<size_t, size_t> getChannelRange() const
+    { return itsChannelRange; }
+
+//    size_t getChannelStep() const
+//    { return itsChannelStep; }
+
+    pair<double, double> getTimeRange() const
+    { return itsTimeRange; }
+
+    set<string> getCorrelations() const
+    { return itsCorrelations; }
+
+    set<string> getStations() const
+    { return itsStations; }
+
+    BaselineFilter getBaselineFilter() const
+    { return itsBaselineFilter; }
+
+//    void selectFreqRange(const pair<uint, uint> &range);
+//    void selectBaselines(const vector<string> &stations);
+//    void selectBaselines(
+//        const pair<vector<string>, vector<string> > &baselines);
+
+private:
+    bool convertTime(const string &in, double &out) const;
+    vector<bool>            itsFieldFlags;
+    pair<size_t, size_t>    itsChannelRange;
+//    size_t                  itsChannelStep;
+//    pair<double, double>    itsFreqRange;
+    pair<double, double>    itsTimeRange;
+//    set<pair<uint, uint> >  itsBaselines;
+    set<string>             itsCorrelations;
+    set<string>             itsStations;
+    BaselineFilter          itsBaselineFilter;
+};
+
+} //# namespace BBS
+} //# namespace LOFAR
+
+#endif
diff --git a/CEP/BB/BBSKernel/src/MNS/MeqBaseDFTPS.cc b/CEP/BB/BBSKernel/src/MNS/MeqBaseDFTPS.cc
index 5a9e6ba2121ec008dbb1ef2fca70df442b0ac8a2..dc78008254dfa22ab1af6ff23ef4be2d05d1319f 100644
--- a/CEP/BB/BBSKernel/src/MNS/MeqBaseDFTPS.cc
+++ b/CEP/BB/BBSKernel/src/MNS/MeqBaseDFTPS.cc
@@ -23,8 +23,11 @@
 #include <lofar_config.h>
 
 #include <BBSKernel/MNS/MeqBaseDFTPS.h>
+#include <BBSKernel/MNS/MeqDFTPS.h>
+#include <BBSKernel/MNS/MeqStatUVW.h>
 #include <BBSKernel/MNS/MeqMatrixTmp.h>
 #include <Common/LofarLogger.h>
+#include <Common/lofar_iomanip.h>
 
 using namespace casa;
 
@@ -105,20 +108,28 @@ MeqResult MeqBaseDFTPS::getResult (const MeqRequest& request)
   // complex numbers which can be turned into a cheaper multiplication.
   //  exp(x)/exp(y) = (cos(x) + i.sin(x)) / (cos(y) + i.sin(y))
   //                = (cos(x) + i.sin(x)) * (cos(y) - i.sin(y))
-    {
-      //const MeqResult& ul = itsLeft->uvw().getU(request);
-      //const MeqResult& vl = itsLeft->uvw().getV(request);
-      //const MeqResult& wl = itsLeft->uvw().getW(request);
-      //const MeqResult& ur = itsRight->uvw().getU(request);
-      //const MeqResult& vr = itsRight->uvw().getV(request);
-      //const MeqResult& wr = itsRight->uvw().getW(request);
-      //cout << "U: " << ur.getValue() - ul.getValue() << endl;
-      //cout << "V: " << vr.getValue() - vl.getValue() << endl;
-      //cout << "W: " << wr.getValue() - wl.getValue() << endl;
-      //LOG_TRACE_FLOW ("U: " << ur.getValue() - ul.getValue());
-      //LOG_TRACE_FLOW ("V: " << vr.getValue() - vl.getValue());
-      //LOG_TRACE_FLOW ("W: " << wr.getValue() - wl.getValue());
-    }
+/*    {
+
+      MeqDFTPS *dftpsl = dynamic_cast<MeqDFTPS*>(itsLeft.rep());
+      MeqDFTPS *dftpsr = dynamic_cast<MeqDFTPS*>(itsRight.rep());
+
+      const MeqResult& ul = dftpsl->uvw()->getU(request);
+      const MeqResult& vl = dftpsl->uvw()->getV(request);
+      const MeqResult& wl = dftpsl->uvw()->getW(request);
+      const MeqResult& ur = dftpsr->uvw()->getU(request);
+      const MeqResult& vr = dftpsr->uvw()->getV(request);
+      const MeqResult& wr = dftpsr->uvw()->getW(request);
+      cout << "U: " << setprecision(20) << ur.getValue() - ul.getValue()
+        << endl;
+      cout << "V: " << setprecision(20) << vr.getValue() - vl.getValue()
+        << endl;
+      cout << "W: " << setprecision(20) << wr.getValue() - wl.getValue()
+        << endl;*/
+//      LOG_TRACE_FLOW ("U: " << ur.getValue() - ul.getValue());
+//      LOG_TRACE_FLOW ("V: " << vr.getValue() - vl.getValue());
+//      LOG_TRACE_FLOW ("W: " << wr.getValue() - wl.getValue());
+//     }
+
   MeqMatrix res(makedcomplex(0,0), request.nx(), request.ny(), false);
   for (int iy=0; iy<request.ny(); ++iy) {
     dcomplex tmpl = left.getValue().getDComplex(0,iy);
@@ -126,7 +137,8 @@ MeqResult MeqBaseDFTPS::getResult (const MeqRequest& request)
     // We have to divide by N.
     // However, we divide by 2N to get the factor 0.5 needed in (I+Q)/2, etc.
     // in MeqBaseLinPS.
-    double tmpnk = 2. * nk.getValue().getDouble(0,iy);
+//    double tmpnk = 2. * nk.getValue().getDouble(0,iy);
+    double tmpnk = 2.0;
     dcomplex factor;
     if (multFreq) {
       dcomplex deltal = leftDelta.getValue().getDComplex(0,iy);
@@ -137,6 +149,9 @@ MeqResult MeqBaseDFTPS::getResult (const MeqRequest& request)
   }
   result.setValue (res);
 
+//  cout << "DFT:" << endl;
+//  cout << setprecision(20) << res << endl;
+
   // Evaluate (if needed) for the perturbed parameter values.
   // Note that we do not have to test for perturbed values in nk,
   // because the left and right value already depend on nk.
@@ -155,7 +170,8 @@ MeqResult MeqBaseDFTPS::getResult (const MeqRequest& request)
       for (int iy=0; iy<request.ny(); ++iy) {
     dcomplex tmpl = left.getPerturbedValue(spinx).getDComplex(0,iy);
     dcomplex tmpr = right.getPerturbedValue(spinx).getDComplex(0,iy);
-    double tmpnk = 2. * nk.getPerturbedValue(spinx).getDouble(0,iy);
+//    double tmpnk = 2. * nk.getPerturbedValue(spinx).getDouble(0,iy);
+    double tmpnk = 2.0;
     dcomplex factor;
     if (multFreq) {
       dcomplex deltal = leftDelta.getPerturbedValue(spinx).getDComplex(0,iy);
diff --git a/CEP/BB/BBSKernel/src/MNS/MeqExpr.cc b/CEP/BB/BBSKernel/src/MNS/MeqExpr.cc
index 92af4b8ccf48f54562d1bb88a1760ae774aedd0f..adc4826e0c766d2cd4473193ce69da67db47526e 100644
--- a/CEP/BB/BBSKernel/src/MNS/MeqExpr.cc
+++ b/CEP/BB/BBSKernel/src/MNS/MeqExpr.cc
@@ -261,11 +261,12 @@ void MeqExprRep::writeExpressionGraph(std::ostream &os)
 {
     os << "id" << std::hex << this << " [label=\"" << getLabel() << "\"];" << std::endl;
 
-    std::vector<MeqExprRep*>::const_iterator it;
+    std::vector<MeqExpr>::iterator it;
     for(it = itsChildren.begin(); it != itsChildren.end(); ++it)
     {
-          os << "id" << std::hex << (*it) << " -> " << "id" << std::hex << this << ";" << std::endl;
-          (*it)->writeExpressionGraph(os);
+          os << "id" << std::hex << it->rep() << " -> " << "id" << std::hex
+            << this << ";" << std::endl;
+          it->writeExpressionGraph(os);
     }
 }
 #endif
diff --git a/CEP/BB/BBSKernel/src/MNS/MeqJonesVisData.cc b/CEP/BB/BBSKernel/src/MNS/MeqJonesVisData.cc
new file mode 100644
index 0000000000000000000000000000000000000000..08757f853feed91ed70a41fc1acb69fe0ddc990d
--- /dev/null
+++ b/CEP/BB/BBSKernel/src/MNS/MeqJonesVisData.cc
@@ -0,0 +1,167 @@
+//# MeqJonesVisData.cc: 
+//#
+//# Copyright (C) 2007
+//# ASTRON (Netherlands Foundation for Research in Astronomy)
+//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//# This program 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 2 of the License, or
+//# (at your option) any later version.
+//#
+//# This program 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 this program; if not, write to the Free Software
+//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//# $Id$
+
+#include <lofar_config.h>
+
+#include <BBSKernel/Exceptions.h>
+#include <BBSKernel/MNS/MeqJonesVisData.h>
+#include <Common/LofarLogger.h>
+
+namespace LOFAR
+{
+namespace BBS
+{
+
+MeqJonesVisData::MeqJonesVisData(VisData::Pointer vdata, baseline_t baseline)
+    : itsVisData(vdata)
+{
+    itsBaselineIndex = itsVisData->getBaselineIndex(baseline);
+}
+
+MeqJonesResult MeqJonesVisData::getJResult (const MeqRequest& request)
+{
+    typedef boost::multi_array<sample_t, 4>::index_range range;
+
+    size_t nChannels = request.nx();
+    size_t nTimeslots = request.ny();
+    pair<size_t, size_t> offset = request.offset();
+    range freqRange(offset.first, offset.first + nChannels);
+    range timeRange(offset.second, offset.second + nTimeslots);
+
+    // Allocate the result matrices.
+    size_t pol;
+    double *re, *im;
+    MeqJonesResult result(request.nspid());
+    MeqMatrix& m11 = result.result11().getValueRW();
+    MeqMatrix& m12 = result.result12().getValueRW();
+    MeqMatrix& m21 = result.result21().getValueRW();
+    MeqMatrix& m22 = result.result22().getValueRW();
+    m11.setDCMat(nChannels, nTimeslots);
+    m12.setDCMat(nChannels, nTimeslots);
+    m21.setDCMat(nChannels, nTimeslots);
+    m22.setDCMat(nChannels, nTimeslots);
+
+    // Copy 11 elements if available.
+    if(itsVisData->hasPolarization("XX") || itsVisData->hasPolarization("LL"))
+    {
+        m11.dcomplexStorage(re, im);
+
+        try
+        {
+            pol = itsVisData->getPolarizationIndex("XX");
+        }
+        catch(BBSKernelException &ex)
+        {
+            pol = itsVisData->getPolarizationIndex("LL");
+        }
+
+        copy(re, im, itsVisData->vis_data[boost::indices[itsBaselineIndex]
+            [timeRange][freqRange][pol]]);
+    }
+    else
+        m11 = MeqMatrix(makedcomplex(0,0), nChannels, nTimeslots);
+
+
+    // Copy 12 elements if available.
+    if(itsVisData->hasPolarization("XY") || itsVisData->hasPolarization("LR"))
+    {
+        m12.dcomplexStorage(re, im);
+
+        try
+        {
+            pol = itsVisData->getPolarizationIndex("XY");
+        }
+        catch(BBSKernelException &ex)
+        {
+            pol = itsVisData->getPolarizationIndex("LR");
+        }
+
+        copy(re, im, itsVisData->vis_data[boost::indices[itsBaselineIndex]
+            [timeRange][freqRange][pol]]);
+    }
+    else
+        m12 = MeqMatrix(makedcomplex(0,0), nChannels, nTimeslots);
+
+
+    // Copy 21 elements if available.
+    if(itsVisData->hasPolarization("YX") || itsVisData->hasPolarization("RL"))
+    {
+        m21.dcomplexStorage(re, im);
+
+        try
+        {
+            pol = itsVisData->getPolarizationIndex("YX");
+        }
+        catch(BBSKernelException &ex)
+        {
+            pol = itsVisData->getPolarizationIndex("RL");
+        }
+
+        copy(re, im, itsVisData->vis_data[boost::indices[itsBaselineIndex]
+            [timeRange][freqRange][pol]]);
+    }
+    else
+        m21 = MeqMatrix(makedcomplex(0,0), nChannels, nTimeslots);
+
+
+    // Copy 22 elements if available.
+    if(itsVisData->hasPolarization("YY") || itsVisData->hasPolarization("RR"))
+    {
+        m22.dcomplexStorage(re, im);
+
+        try
+        {
+            pol = itsVisData->getPolarizationIndex("YY");
+        }
+        catch(BBSKernelException &ex)
+        {
+            pol = itsVisData->getPolarizationIndex("RR");
+        }
+
+        copy(re, im, itsVisData->vis_data[boost::indices[itsBaselineIndex]
+            [timeRange][freqRange][pol]]);
+    }
+    else
+        m22 = MeqMatrix(makedcomplex(0,0), nChannels, nTimeslots);
+
+    return result;
+}
+
+
+void MeqJonesVisData::copy(double *re, double *im,
+    const boost::multi_array<sample_t, 4>::const_array_view<2>::type &src)
+{
+    for(size_t tslot = 0; tslot < src.shape()[0]; ++tslot)
+    {
+        for(size_t chan = 0; chan < src.shape()[1]; ++chan)
+        {
+            re[chan] = real(src[tslot][chan]);
+            im[chan] = imag(src[tslot][chan]);
+        }
+        re += src.shape()[1];
+        im += src.shape()[1];
+    }
+}
+
+
+} // namespace BBS
+} // namespace LOFAR
diff --git a/CEP/BB/BBSKernel/src/MNS/MeqParm.cc b/CEP/BB/BBSKernel/src/MNS/MeqParm.cc
index d6ff1e65acd15e97ede08814aea406811bda15fa..d6b07958054cba56b09ccd911cc598b5fdee1641 100644
--- a/CEP/BB/BBSKernel/src/MNS/MeqParm.cc
+++ b/CEP/BB/BBSKernel/src/MNS/MeqParm.cc
@@ -66,6 +66,9 @@ int MeqParm::initDomain (const vector<MeqDomain>&, int&, vector<int>&)
 void MeqParm::save()
 {}
 
+void MeqParm::save(size_t domainIndex)
+{}
+
 void MeqParm::update (const ParmData&)
 {
   throw Exception("MeqParm::update ParmData should not be called");
diff --git a/CEP/BB/BBSKernel/src/MNS/MeqParmFunklet.cc b/CEP/BB/BBSKernel/src/MNS/MeqParmFunklet.cc
index 0ba80879c54e11022f2111bbf20e2ed614ac2d99..d0c88f4084ae93fab280225e4abddb83560b7af9 100644
--- a/CEP/BB/BBSKernel/src/MNS/MeqParmFunklet.cc
+++ b/CEP/BB/BBSKernel/src/MNS/MeqParmFunklet.cc
@@ -409,5 +409,14 @@ void MeqParmFunklet::update(size_t domainIndex, size_t unknownIndex, const vecto
     itsFunklets[domainIndex]->update(unknownIndex, unknowns);
 }
 
+void MeqParmFunklet::save(size_t domainIndex)
+{
+  ASSERT(domainIndex < itsFunklets.size());
+  //itsTable->lock();
+  LOFAR::ParmDB::ParmValue pval = itsFunklets[domainIndex]->getParmValue();
+  itsTable->putValue(getName(), pval);
+  //itsTable->unlock();
+}
+
 } // namespace BBS
 } // namespace LOFAR
diff --git a/CEP/BB/BBSKernel/src/MNS/MeqRequest.cc b/CEP/BB/BBSKernel/src/MNS/MeqRequest.cc
index 0dff4f6a3a2466d1989b3729956b816752145f22..96748f66cf7f8d37b1a1f0b7e92a9b771a682afe 100644
--- a/CEP/BB/BBSKernel/src/MNS/MeqRequest.cc
+++ b/CEP/BB/BBSKernel/src/MNS/MeqRequest.cc
@@ -35,7 +35,7 @@ MeqRequestId MeqRequest::theirRequestId = 0;
 
 MeqRequest::MeqRequest (const MeqDomain& domain, int nx, int ny, int nrSpid)
 : itsRequestId (theirRequestId++),
-  itsFirstX    (0),
+  itsOffset    (0, 0),
   itsSourceNr  (0),
   itsNspids    (nrSpid)
 {
@@ -46,7 +46,7 @@ MeqRequest::MeqRequest (const MeqDomain& domain, int nx,
 			const vector<double>& y,
 			int nrSpid)
 : itsRequestId (theirRequestId++),
-  itsFirstX    (0),
+  itsOffset    (0, 0),
   itsSourceNr  (0),
   itsNspids    (nrSpid)
 {
@@ -57,7 +57,7 @@ MeqRequest::MeqRequest (const MeqRequest& req,
 			uint stx, uint nrx, uint sty, uint nry)
 : itsRequestId (req.itsRequestId),
   itsStepX     (req.itsStepX),
-  itsFirstX    (req.itsFirstX),
+  itsOffset    (req.itsOffset),
   itsSourceNr  (req.itsSourceNr),
   itsNspids    (req.itsNspids)
 {
@@ -78,7 +78,7 @@ MeqRequest::MeqRequest (const MeqRequest& req)
   itsStepX     (req.itsStepX),
   itsY         (req.itsY),
   itsYP        (req.itsYP),
-  itsFirstX    (req.itsFirstX),
+  itsOffset    (req.itsOffset),
   itsSourceNr  (req.itsSourceNr),
   itsNspids    (req.itsNspids)
 {
@@ -97,7 +97,7 @@ MeqRequest& MeqRequest::operator= (const MeqRequest& req)
     itsStepX     = req.itsStepX;
     itsY         = req.itsY;
     itsYP        = req.itsYP;
-    itsFirstX    = req.itsFirstX;
+    itsOffset    = req.itsOffset;
     itsSourceNr  = req.itsSourceNr;
     itsNspids    = req.itsNspids;
     if (itsY.size() > 0) {
diff --git a/CEP/BB/BBSKernel/src/MNS/MeqStatUVW.cc b/CEP/BB/BBSKernel/src/MNS/MeqStatUVW.cc
index f4cf064113ddc3f01dd89bd4f57430c790c59780..dc5652312dfae1f4ea210be61c352c31b27adc0d 100644
--- a/CEP/BB/BBSKernel/src/MNS/MeqStatUVW.cc
+++ b/CEP/BB/BBSKernel/src/MNS/MeqStatUVW.cc
@@ -31,10 +31,10 @@
 
 #include <measures/Measures/MBaseline.h>
 #include <measures/Measures/MEpoch.h>
-#include <measures/Measures/MCBaseline.h>
 #include <measures/Measures/MeasConvert.h>
 #include <measures/Measures/MeasFrame.h>
 #include <casa/Quanta/MVuvw.h>
+#include <stdint.h>
 
 using namespace casa;
 
@@ -62,11 +62,11 @@ MeqStatUVW::MeqStatUVW (MeqStation* station,
 }
 */
 
-
-MeqStatUVW::MeqStatUVW(MeqStation* station, const pair<double, double> &phaseCenter, const vector<double> &arrayPosition)
-: itsStation   (station),
-  itsPhaseCenter(MVDirection(phaseCenter.first, phaseCenter.second), MDirection::J2000),
-  itsArrayPosition(MVPosition(arrayPosition[0], arrayPosition[1], arrayPosition[2]), MPosition::ITRF),
+MeqStatUVW::MeqStatUVW(MeqStation *station, const casa::MDirection &phaseCenter,
+    const casa::MPosition &arrayPosition)
+    :   itsStation(station),
+        itsPhaseCenter(phaseCenter),
+        itsArrayPosition(arrayPosition),
   itsU         (0),
   itsV         (0),
   itsW         (0),
@@ -82,7 +82,7 @@ void MeqStatUVW::calculate (const MeqRequest& request)
   double* uptr = itsU.setDoubleFormat (1, ntime);
   double* vptr = itsV.setDoubleFormat (1, ntime);
   double* wptr = itsW.setDoubleFormat (1, ntime);
-  
+
   //# Use the UVW coordinates if already calculated for a time.
   int ndone = 0;
   for (int i=0; i<ntime; ++i) {
@@ -100,59 +100,64 @@ void MeqStatUVW::calculate (const MeqRequest& request)
     itsLastReqId = request.getId();
     return;
   }
-  
+
   //# Calculate the other UVW coordinates using the AIPS++ code.
   //# First form the time-independent stuff.
   ASSERTSTR (itsStation, "UVW coordinates cannot be calculated");
-  
+
   //# Get station coordinates in ITRF coordinates
   MeqResult posx = itsStation->getPosX().getResult (request);
   MeqResult posy = itsStation->getPosY().getResult (request);
   MeqResult posz = itsStation->getPosZ().getResult (request);
-  
+
   LOG_TRACE_FLOW_STR ("posx" << posx.getValue());
   LOG_TRACE_FLOW_STR ("posy" << posy.getValue());
   LOG_TRACE_FLOW_STR ("posz" << posz.getValue());
-  
+
   //# Get position relative to center to keep values small.
 //#  const MVPosition& mvcpos = itsPhaseRef->earthPosition().getValue();
   const MVPosition& mvcpos = itsArrayPosition.getValue();
   MVPosition mvpos(posx.getValue().getDouble() - mvcpos(0),
                    posy.getValue().getDouble() - mvcpos(1),
                    posz.getValue().getDouble() - mvcpos(2));
-                   
-  MVBaseline mvbl(mvpos);
-  MBaseline mbl(mvbl, MBaseline::ITRF);
-  LOG_TRACE_FLOW_STR ("mbl " << mbl);
-  
-  Quantum<double> qepoch(0, "s");
-//# ?? qepoch.setValue(time(0)) ??
-  MEpoch mepoch(qepoch, MEpoch::UTC);
-//#  itsFrame.set (mepoch);
-  MeasFrame frame(itsArrayPosition);
-  frame.set(itsPhaseCenter);
-  frame.set(mepoch);
-  
+
+//  LOG_TRACE_FLOW_STR ("mbl " << mbl);
 //#  mbl.getRefPtr()->set(itsFrame);      // attach frame
-  mbl.getRefPtr()->set(frame);      // attach frame
-  
-  MBaseline::Convert mcvt(mbl, MBaseline::J2000);
-  
+
+
   for (int i=0; i<ntime; ++i) {
     double time = request.y(i);
+//    cout << "Time: " << setprecision(25) << time << endl;
     map<MeqTime,MeqUVW>::iterator pos = itsUVW.find (MeqTime(time));
     if (pos == itsUVW.end()) {
-      qepoch.setValue(time);
-      mepoch.set(qepoch);
-      frame.set(mepoch);
 
-      LOG_TRACE_FLOW_STR ("frame " << mbl.getRefPtr()->getFrame());
+      Quantum<double> qepoch(time, "s");
+      MEpoch mepoch(qepoch, MEpoch::UTC);
 
+      MeasFrame frame(itsArrayPosition);
+      frame.set(itsPhaseCenter);
+      frame.set(mepoch);
+
+//      cout << "Frame: " << setprecision(25) << frame << endl;
+//      LOG_TRACE_FLOW_STR ("frame " << mbl.getRefPtr()->getFrame());
+
+      MVBaseline mvbl(mvpos);
+//      cout << "mvbl: " << setprecision(25) << mvbl << endl;
+      MBaseline mbl(mvbl, MBaseline::ITRF);
+//      cout << "mbl: " << setprecision(25) << mbl << endl;
+      mbl.getRefPtr()->set(frame);      // attach frame
+//      cout << "mbl (after set frame): " << setprecision(25) << mbl << endl;
+      MBaseline::Convert mcvt(mbl, MBaseline::J2000);
+//      cout << "mcvt: " << setprecision(25) << mcvt << endl;
       const MVBaseline& bas2000 = mcvt().getValue();
-      LOG_TRACE_FLOW_STR (bas2000);
+//      cout << "bas2000: " << setprecision(25) << bas2000 << endl;
+
+//      LOG_TRACE_FLOW_STR (bas2000);
 //#      LOG_TRACE_FLOW_STR (itsPhaseRef->direction().getValue());
-      LOG_TRACE_FLOW_STR (itsPhaseCenter.getValue());
+//      LOG_TRACE_FLOW_STR (itsPhaseCenter.getValue());
 //#      MVuvw uvw2000 (bas2000, itsPhaseRef->direction().getValue());
+
+
       MVuvw uvw2000 (bas2000, itsPhaseCenter.getValue());
 
       const Vector<double>& xyz = uvw2000.getValue();
@@ -161,6 +166,15 @@ void MeqStatUVW::calculate (const MeqRequest& request)
       *uptr++ = xyz(0);
       *vptr++ = xyz(1);
       *wptr++ = xyz(2);
+/*
+      cout << "Baseline: " << hex
+<< *reinterpret_cast<unsigned long long int*>(const_cast<double*>(&(xyz(0))))
+<< " " << hex
+<< *reinterpret_cast<unsigned long long int*>(const_cast<double*>(&(xyz(1))))
+<< " " << hex
+<< *reinterpret_cast<unsigned long long int*>(const_cast<double*>(&(xyz(2))))
+<< dec << endl;
+*/
       // Save the UVW coordinates in the map.
       itsUVW[MeqTime(time)] = MeqUVW(xyz(0), xyz(1), xyz(2));
     }
@@ -168,6 +182,13 @@ void MeqStatUVW::calculate (const MeqRequest& request)
   LOG_TRACE_FLOW_STR ('U' << itsU.getValue());
   LOG_TRACE_FLOW_STR ('V' << itsV.getValue());
   LOG_TRACE_FLOW_STR ('W' << itsW.getValue());
+
+/*
+  cout << "Station: " << itsStation->getName() << endl;
+  cout << "U: " << setprecision(25) << itsU.getValue() << endl;
+  cout << "V: " << setprecision(25) << itsV.getValue() << endl;
+  cout << "W: " << setprecision(25) << itsW.getValue() << endl;
+*/
   itsLastReqId = request.getId();
 }
 
diff --git a/CEP/BB/BBSKernel/src/Makefile.am b/CEP/BB/BBSKernel/src/Makefile.am
index be007320c9b14ace88260d3c339824d33d90bfd3..f7832b58d49f93d3cf66c27a1deb1ee844e0ebec 100644
--- a/CEP/BB/BBSKernel/src/Makefile.am
+++ b/CEP/BB/BBSKernel/src/Makefile.am
@@ -3,17 +3,11 @@ lib_LTLIBRARIES = libbbskernel.la
 libbbskernel_la_SOURCES = 	\
 	BBSKernelStructs.cc	\
 	BBSStatus.cc		\
-	BBSTestLogger.cc	\
-	FlagsMap.cc		\
-	MMap.cc			\
-	MMapMSInfo.cc		\
-	ParmData.cc		\
-	ParmWriter.cc		\
+	MeasurementAIPS.cc	\
+	Model.cc		\
 	Prediffer.cc		\
-	Quality.cc		\
-	Solver.cc		\
-	StepProp.cc		\
-	StrategyProp.cc		\
+	VisData.cc		\
+	VisSelection.cc		\
 	MNS/MeqBaseDFTPS.cc	\
 	MNS/MeqBaseLinPS.cc	\
 	MNS/MeqDFTPS.cc		\
@@ -26,11 +20,11 @@ libbbskernel_la_SOURCES = 	\
 	MNS/MeqJonesCMul3.cc	\
 	MNS/MeqJonesExpr.cc	\
 	MNS/MeqJonesInvert.cc	\
-	MNS/MeqJonesMMap.cc	\
 	MNS/MeqJonesMul2.cc	\
 	MNS/MeqJonesMul3.cc	\
 	MNS/MeqJonesNode.cc	\
 	MNS/MeqJonesSum.cc	\
+	MNS/MeqJonesVisData.cc	\
 	MNS/MeqLMN.cc		\
 	MNS/MeqMatrix.cc	\
 	MNS/MeqMatrixComplexArr.cc \
@@ -57,10 +51,4 @@ libbbskernel_la_SOURCES = 	\
 	MNS/MeqStatUVW.cc	\
 	MNS/MeqTabular.cc 
 
-bin_PROGRAMS = BBSrun
-
-BBSrun_SOURCES 		= BBSrun.cc
-BBSrun_LDADD 		= libbbskernel.la
-BBSrun_DEPENDENCIES 	= libbbskernel.la $(LOFAR_DEPEND)
-
 include $(top_srcdir)/Makefile.common
diff --git a/CEP/BB/BBSKernel/src/MeasurementAIPS.cc b/CEP/BB/BBSKernel/src/MeasurementAIPS.cc
new file mode 100644
index 0000000000000000000000000000000000000000..cdd7e653fdbd8297ce0af9d9877d7045cab4ab0d
--- /dev/null
+++ b/CEP/BB/BBSKernel/src/MeasurementAIPS.cc
@@ -0,0 +1,750 @@
+//# MeasurementAIPS.cc: 
+//#
+//# Copyright (C) 2007
+//# ASTRON (Netherlands Foundation for Research in Astronomy)
+//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//# This program 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 2 of the License, or
+//# (at your option) any later version.
+//#
+//# This program 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 this program; if not, write to the Free Software
+//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//# $Id$
+
+#include <lofar_config.h>
+#include <BBSKernel/MeasurementAIPS.h>
+
+#include <cstring>
+#include <Common/Timer.h>
+#include <Common/lofar_algorithm.h>
+#include <Common/LofarLogger.h>
+#include <Common/StreamUtil.h>
+
+//#include <casa/Arrays/Slicer.h>
+//#include <casa/Arrays/Vector.h>
+// Vector2.cc: necessary to instantiate .tovector()
+//#include <casa/Arrays/Vector2.cc>
+
+#include <measures/Measures/MeasTable.h>
+#include <measures/Measures/MeasConvert.h>
+
+#include <tables/Tables/Table.h>
+#include <tables/Tables/ExprNode.h>
+#include <tables/Tables/ExprNodeSet.h>
+#include <tables/Tables/TableIter.h>
+#include <tables/Tables/ScalarColumn.h>
+#include <tables/Tables/ArrayColumn.h>
+
+//#include <tables/Tables/TableDesc.h>
+//#include <tables/Tables/ScalarColumn.h>
+#include <tables/Tables/ArrColDesc.h>
+#include <tables/Tables/TiledColumnStMan.h>
+
+//#include <tables/Tables/ArrColDesc.h>
+//#include <tables/Tables/TiledColumnStMan.h>
+#include <casa/Arrays/ArrayLogical.h>
+#include <casa/Arrays/Matrix.h>
+#include <casa/Arrays/Cube.h>
+
+#include <ms/MeasurementSets/MSAntenna.h>
+#include <ms/MeasurementSets/MSAntennaColumns.h>
+#include <ms/MeasurementSets/MSDataDescription.h>
+#include <ms/MeasurementSets/MSDataDescColumns.h>
+#include <ms/MeasurementSets/MSField.h>
+#include <ms/MeasurementSets/MSFieldColumns.h>
+#include <ms/MeasurementSets/MSObservation.h>
+#include <ms/MeasurementSets/MSObsColumns.h>
+#include <ms/MeasurementSets/MSPolarization.h>
+#include <ms/MeasurementSets/MSPolColumns.h>
+#include <ms/MeasurementSets/MSSpectralWindow.h>
+#include <ms/MeasurementSets/MSSpWindowColumns.h>
+
+#include <casa/Utilities/GenSort.h>
+
+#include <Common/lofar_iomanip.h>
+
+using namespace casa;
+using namespace std;
+
+namespace LOFAR
+{
+namespace BBS 
+{
+
+MeasurementAIPS::MeasurementAIPS(string filename,
+        uint observationId,
+        uint dataDescriptionId,
+        uint fieldId)
+        :   itsFilename(filename),
+            itsObservationId(observationId),
+            itsDataDescriptionId(dataDescriptionId),
+            itsFieldId(fieldId)
+{
+    itsMS = casa::MeasurementSet(itsFilename);
+
+    itsInstrument = readInstrumentInfo(itsMS.antenna(), itsMS.observation(),
+        itsObservationId);
+
+    // Read time range.
+    MSObservation observation(itsMS.observation());
+    ROMSObservationColumns observationCols(observation);
+
+    ASSERT(observation.nrow() > observationId);
+    ASSERT(!observationCols.flagRow()(observationId));
+
+    const Vector<MEpoch> timeRange =
+        observationCols.timeRangeMeas()(observationId);
+
+    itsTimeRange = make_pair(timeRange(0), timeRange(1));
+
+    // Read polarization id and spectral window id.
+    ROMSDataDescColumns dataDescription(itsMS.dataDescription());
+    ASSERT(itsMS.dataDescription().nrow() > dataDescriptionId);
+    ASSERT(!dataDescription.flagRow()(dataDescriptionId));
+
+    Int polarizationId =
+        dataDescription.polarizationId()(dataDescriptionId);
+
+    Int spectralWindowId =
+        dataDescription.spectralWindowId()(dataDescriptionId);
+
+    itsCorrelationProducts =
+        readPolarizationInfo(itsMS.polarization(), polarizationId);
+
+    readSpectralInfo(itsMS.spectralWindow(), spectralWindowId);
+    itsPhaseCenter = readFieldInfo(itsMS.field(), itsFieldId);
+
+    // Select all rows that match the specified observation.
+    itsMS = itsMS(itsMS.col("OBSERVATION_ID") == itsObservationId
+        && itsMS.col("DATA_DESC_ID") == itsDataDescriptionId
+        && itsMS.col("FIELD_ID") == itsFieldId);
+
+    // Sort MS on TIME.
+    itsMS.sort("TIME");
+
+    LOG_DEBUG_STR("Measurement " << itsObservationId << " contains "
+        << itsMS.nrow() << " row(s).");
+}
+
+
+MeasurementAIPS::~MeasurementAIPS()
+{
+    itsMS = MeasurementSet();
+}
+
+
+VisGrid MeasurementAIPS::grid(const VisSelection &selection) const
+{
+    TableExprNode taqlExpr = getTAQLExpression(selection);
+    Slicer slicer = getCellSlicer(selection);
+
+    Table tab_selection = itsMS(taqlExpr);
+    ASSERTSTR(tab_selection.nrow() > 0, "Data selection empty!");
+
+    return getGrid(tab_selection, slicer);
+}
+
+
+VisData::Pointer MeasurementAIPS::read(const VisSelection &selection,
+    const string &column,
+    bool readUVW) const
+{
+    NSTimer readTimer, copyTimer;
+
+    TableExprNode taqlExpr = getTAQLExpression(selection);
+    Slicer slicer = getCellSlicer(selection);
+
+    Table tab_selection = itsMS(taqlExpr);
+    ASSERTSTR(tab_selection.nrow() > 0, "Data selection empty!");
+
+    VisGrid grid = getGrid(tab_selection, slicer);
+    VisData::Pointer buffer = allocate(grid);
+
+    size_t nChannels = buffer->freq.size();
+    size_t nCorrelations = getCorrelationCount();
+
+    TableIterator tslotIterator(tab_selection, "TIME");
+
+    Table tslot;
+    uint32 tslotIdx = 0;
+    while(!tslotIterator.pastEnd())
+    {
+        ASSERT(tslotIdx < buffer->getTimeslotCount());
+
+        // Get next timeslot.
+        tslot = tslotIterator.table();
+
+        // Declare all the columns we want to read.
+        ROScalarColumn<Int> c_antenna1(tslot, "ANTENNA1");
+        ROScalarColumn<Int> c_antenna2(tslot, "ANTENNA2");
+        ROScalarColumn<Bool> c_flag_row(tslot, "FLAG_ROW");
+        ROArrayColumn<Double> c_uvw(tslot, "UVW");
+        ROArrayColumn<Complex> c_data(tslot, column);
+        ROArrayColumn<Bool> c_flag(tslot, "FLAG");
+
+        // Read data from the MS.
+        readTimer.start();
+        Vector<Int> aips_antenna1 = c_antenna1.getColumn();
+        Vector<Int> aips_antenna2 = c_antenna2.getColumn();
+        Vector<Bool> aips_flag_row = c_flag_row.getColumn();
+        Matrix<Double> aips_uvw;
+        if(readUVW)
+             aips_uvw = c_uvw.getColumn();
+
+        Cube<Complex> aips_data = c_data.getColumn(slicer);
+        Cube<Bool> aips_flag = c_flag.getColumn(slicer);
+        readTimer.stop();
+
+        // Validate shapes.
+        ASSERT(aips_antenna1.shape().isEqual(IPosition(1,tslot.nrow())));
+        ASSERT(aips_antenna2.shape().isEqual(IPosition(1,tslot.nrow())));
+        ASSERT(aips_flag_row.shape().isEqual(IPosition(1, tslot.nrow())));
+        ASSERT(!readUVW
+            || aips_uvw.shape().isEqual(IPosition(2, 3, tslot.nrow())));
+        IPosition shape = IPosition(3, nCorrelations, nChannels, tslot.nrow());
+        ASSERT(aips_data.shape().isEqual(shape));
+        ASSERT(aips_flag.shape().isEqual(shape));
+
+        ASSERT(aips_data.contiguousStorage());
+        ASSERT(aips_flag.contiguousStorage());
+
+        // The const_cast<>() call below is needed becase multi_array_ref
+        // expects a non-const pointer. This does not break the const semantics
+        // as we never write to the array.
+        Complex *ptr_data = const_cast<Complex*>(aips_data.data());
+        boost::multi_array_ref<sample_t, 3>
+            data(reinterpret_cast<sample_t*>(ptr_data),
+                boost::extents[tslot.nrow()][nChannels][nCorrelations]);
+
+        Bool *ptr_flag = const_cast<Bool*>(aips_flag.data());
+        boost::multi_array_ref<flag_t, 3> flag(ptr_flag,
+                boost::extents[tslot.nrow()][nChannels][nCorrelations]);
+
+        copyTimer.start();
+        for(uInt i = 0; i < tslot.nrow(); ++i)
+        {
+            // Get time sequence for this baseline.
+            map<baseline_t, size_t>::iterator it =
+                buffer->baselines.find(baseline_t(aips_antenna1[i],
+                    aips_antenna2[i]));
+
+            ASSERTSTR(it != buffer->baselines.end(), "Unknown baseline!");
+            size_t baseline = it->second;
+
+            // Flag timeslot as available.
+            buffer->tslot_flag[baseline][tslotIdx] = 0;
+
+            // Copy row (timeslot) flag.
+            if(aips_flag_row(i))
+                buffer->tslot_flag[baseline][tslotIdx] |=
+                    VisData::FLAGGED_IN_INPUT;
+
+            // Copy UVW.
+            if(readUVW)
+            {
+                buffer->uvw[baseline][tslotIdx][0] = aips_uvw(0, i);
+                buffer->uvw[baseline][tslotIdx][1] = aips_uvw(1, i);
+                buffer->uvw[baseline][tslotIdx][2] = aips_uvw(2, i);
+            }
+
+            // Copy visibilities.
+            buffer->vis_data[baseline][tslotIdx] = data[i];
+            // Copy flags.
+            buffer->vis_flag[baseline][tslotIdx] = flag[i];
+        }
+        copyTimer.stop();
+
+        // Proceed to the next timeslot.
+        ++tslotIdx;
+        ++tslotIterator;
+    }
+
+    LOG_DEBUG_STR("Read time: " << readTimer);
+    LOG_DEBUG_STR("Copy time: " << copyTimer);
+
+    return buffer;
+}
+
+
+
+void MeasurementAIPS::write(const VisSelection &selection,
+    VisData::Pointer buffer,
+    const string &column,
+    bool writeFlags) const
+{
+    NSTimer readTimer, writeTimer;
+
+    ASSERTSTR(!writeFlags, "Flag writing not implemented yet!");
+
+    // TODO: The addition of a column is not noted by the MeasurementSet
+    // class.
+    Table out(itsFilename);
+    out.reopenRW();
+
+    Slicer slicer = getCellSlicer(selection);
+    size_t nChannels = buffer->freq.size();
+    size_t nCorrelations = getCorrelationCount();
+
+    // Add column if it does not exist.
+    // TODO: Check why the AIPS++ imager does not recognize these columns.
+    if(!out.tableDesc().isColumn(column))
+    {
+        LOG_INFO_STR("Adding column '" << column << "'.");
+
+        ArrayColumnDesc<Complex> descriptor(column,
+            IPosition(2, nCorrelations, nChannels),
+            ColumnDesc::FixedShape);
+        TiledColumnStMan storageManager("Tiled_" + column,
+            IPosition(3, nCorrelations, nChannels, 1));
+
+        out.addColumn(descriptor, storageManager);
+        out.flush();
+    }
+
+    LOG_DEBUG_STR("Writing to column: " << column);
+
+    TableExprNode taqlExpr = getTAQLExpression(selection);
+    Table tab_selection = itsMS(taqlExpr);
+    ASSERTSTR(tab_selection.nrow() > 0, "Data selection empty!");
+
+    Table tslot;
+    size_t tslotIdx = 0;
+    bool mismatch = false;
+    TableIterator tslotIterator(tab_selection, "TIME");
+    while(!tslotIterator.pastEnd())
+    {
+        ASSERTSTR(tslotIdx < buffer->getTimeslotCount(),
+            "Timeslot out of range!");
+
+        // Extract next timeslot.
+        tslot = tslotIterator.table();
+//        LOG_DEBUG_STR("No. of rows in timeslot " << tslotIdx << ": "
+//            << tslot.nrow());
+
+        // TODO: Should use TIME_CENTROID here (centroid of exposure)?
+        // NOTE: TIME_CENTROID may be different for each baseline!
+        ROScalarColumn<Double> c_time(tslot, "TIME");
+        ROScalarColumn<Int> c_antenna1(tslot, "ANTENNA1");
+        ROScalarColumn<Int> c_antenna2(tslot, "ANTENNA2");
+        ArrayColumn<Complex> c_data(tslot, column);
+        ArrayColumn<Bool> c_flag(tslot, "FLAG");
+
+        // Read meta data.
+        readTimer.start();
+        Vector<Double> aips_time = c_time.getColumn();
+        Vector<Int> aips_antenna1 = c_antenna1.getColumn();
+        Vector<Int> aips_antenna2 = c_antenna2.getColumn();
+        readTimer.stop();
+
+        // Validate shapes.
+        ASSERT(aips_antenna1.shape().isEqual(IPosition(1, tslot.nrow())));
+        ASSERT(aips_antenna2.shape().isEqual(IPosition(1, tslot.nrow())));
+        ASSERT(aips_time.shape().isEqual(IPosition(1, tslot.nrow())));
+
+        mismatch = mismatch && (buffer->time(tslotIdx) == aips_time(0));
+
+        writeTimer.start();
+        for(uInt i = 0; i < tslot.nrow(); ++i)
+        {
+            // Get time sequence for this baseline.
+            map<baseline_t, size_t>::iterator it =
+                buffer->baselines.find(baseline_t(aips_antenna1[i],
+                    aips_antenna2[i]));
+
+            ASSERTSTR(it != buffer->baselines.end(), "Unknown baseline!");
+            size_t baseline = it->second;
+
+            // Write visibilities.
+            Array<Complex> vis_data(IPosition(2, nCorrelations, nChannels),
+                reinterpret_cast<Complex*>
+                    (&(buffer->vis_data[baseline][tslotIdx][0][0])),
+                SHARE);
+            c_data.putSlice(i, slicer, vis_data);
+        }
+        writeTimer.stop();
+
+        ++tslotIdx;
+        ++tslotIterator;
+    }
+    tab_selection.flush();
+
+    if(mismatch)
+        LOG_WARN_STR("Time mismatches detected while writing data.");
+
+    LOG_DEBUG_STR("Read time (meta data): " << readTimer);
+    LOG_DEBUG_STR("Write time: " << writeTimer);
+}
+
+
+Instrument
+MeasurementAIPS::readInstrumentInfo(const casa::MSAntenna &tab_antenna,
+    const casa::MSObservation &tab_observation,
+    uint id)
+{
+    // Get station names and positions in ITRF coordinates.
+    ROMSAntennaColumns antenna(tab_antenna);
+    ROMSObservationColumns observation(tab_observation);
+    ASSERT(tab_observation.nrow() > id);
+    ASSERT(!observation.flagRow()(id));
+
+    Instrument instrument;
+    instrument.name = observation.telescopeName()(id);
+    instrument.stations.resize(tab_antenna.nrow());
+
+    MVPosition stationCentroid;
+    for(size_t i = 0; i < instrument.stations.size(); ++i)
+    {
+        // Store station name and update index.
+        instrument.stations[i].name = antenna.name()(i);
+        instrument.stationIndex[antenna.name()(i)] = i;
+
+        // Store station position.
+        MPosition position = antenna.positionMeas()(i);
+        instrument.stations[i].position =
+            MPosition::Convert(position, MPosition::ITRF)();
+
+        // Update centroid.
+        stationCentroid += instrument.stations[i].position.getValue();
+    }
+
+    // Get the instrument position in ITRF coordinates, or use the centroid
+    // of the station positions if the instrument position is unknown.
+    MPosition instrumentPosition;
+    if(MeasTable::Observatory(instrumentPosition, instrument.name))
+    {
+        instrument.position =
+            MPosition::Convert(instrumentPosition, MPosition::ITRF)();
+    }
+    else
+    {
+        LOG_WARN("Instrument position unknown; will use centroid of stations.");
+        stationCentroid *= (1.0 / (double) instrument.stations.size());
+        instrument.position = MPosition(stationCentroid, MPosition::ITRF);
+    }
+
+    return instrument;
+}
+
+void MeasurementAIPS::readSpectralInfo(const casa::MSSpectralWindow &tab_window,
+    uint id)
+{
+    ROMSSpWindowColumns window(tab_window);
+    ASSERT(tab_window.nrow() > id);
+    ASSERT(!window.flagRow()(id));
+
+    Int nChannels = window.numChan()(id);
+    ASSERT(nChannels > 0);
+
+    Vector<Double> frequency = window.chanFreq()(id);
+    Vector<Double> width = window.chanWidth()(id);
+
+    ASSERT(frequency.nelements() == nChannels);
+    ASSERT(width.nelements() == nChannels);
+    ASSERTSTR(frequency(0) <= frequency(nChannels - 1),
+        "Channels are in reverse order. This is not supported yet.");
+    // TODO: Technically, checking for equal channel widths is not enough,
+    // because there could still be gaps between channels even though the
+    // widths are still equal (this is not prevented by the MS 2.0 standard).
+    ASSERTSTR(allEQ(width, width(0)),
+        "Channels width is not the same for all channels. This is not supported"
+        " yet.");
+
+    double lower = frequency(0) - 0.5 * width(0);
+    double upper = frequency(nChannels - 1) + 0.5 * width(nChannels - 1);
+    regular_series series(lower, (upper - lower) / nChannels);
+    itsSpectrum = cell_centered_axis<regular_series>(series, nChannels);
+}
+
+
+vector<string>
+MeasurementAIPS::readPolarizationInfo(const MSPolarization &tab_polarization,
+    uint id)
+{
+    ROMSPolarizationColumns polarization(tab_polarization);
+    ASSERT(tab_polarization.nrow() > id);
+    ASSERT(!polarization.flagRow()(id));
+
+    Vector<Int> products = polarization.corrType()(id);
+
+    vector<string> result;
+    for(size_t i = 0; i < products.nelements(); ++i)
+        result.push_back(Stokes::name(Stokes::type(products(i))));
+
+    return result;
+}
+
+
+casa::MDirection MeasurementAIPS::readFieldInfo(const MSField &tab_field,
+    uint id)
+{
+    /*
+      Get phase center as RA and DEC (J2000).
+
+      From AIPS++ note 229 (MeasurementSet definition version 2.0):
+      ---
+      FIELD: Field positions for each source
+      Notes:
+      The FIELD table defines a field position on the sky. For interferometers,
+      this is the correlated field position. For single dishes, this is the
+      nominal pointing direction.
+      ---
+
+      In LOFAR/CEP/BB/MS/src/makemsdesc.cc the following line can be found:
+      MDirection phaseRef = mssubc.phaseDirMeasCol()(0)(IPosition(1,0));
+      This should be equivalent to:
+      MDirection phaseRef = mssubc.phaseDirMeas(0);
+      as used in the code below.
+    */
+    ROMSFieldColumns field(tab_field);
+    ASSERT(tab_field.nrow() > id);
+    ASSERT(!field.flagRow()(id));
+
+    return MDirection::Convert(field.phaseDirMeas(id), MDirection::J2000)();
+}
+
+/*
+void Measurement::readTimeInfo(const Table &selection)
+{
+    ROScalarColumn<double> time(selection, "TIME");
+    ROScalarColumn<double> interval(selection, "INTERVAL");
+
+    ASSERT(time.nrow() == interval.nrow() && time.nrow() > 0);
+
+    uint nTimes = time.nrow();
+    itsTimeRange[0] = time(0) - interval(0) / 2.0;
+    itsTimeRange[1] = time(nTimes - 1) + interval(nTimes - 1) / 2.0;
+}
+*/
+
+
+// OPTIMIZATION OPPORTUNITY: Cache implementation specific selection within
+// a specialization of VisSelection or VisData.
+TableExprNode
+MeasurementAIPS::getTAQLExpression(const VisSelection &selection) const
+{
+    TableExprNode filter(true);
+
+    const pair<double, double> &timeRange = selection.getTimeRange();
+    if(selection.isSet(VisSelection::TIME_START))
+    {
+        filter = filter &&
+            itsMS.col("TIME") >= timeRange.first;
+    }
+
+    if(selection.isSet(VisSelection::TIME_END))
+    {
+        filter = filter
+            && itsMS.col("TIME") <= timeRange.second;
+    }
+
+    if(selection.isSet(VisSelection::STATIONS))
+    {
+        set<string> stations = selection.getStations();
+        ASSERT(stations.size() > 0);
+
+        set<size_t> selection;
+        for(set<string>::const_iterator it = stations.begin();
+            it != stations.end();
+            ++it)
+        {
+            casa::Regex regex = casa::Regex::fromPattern(*it);
+
+            // If the name of a station matches the pattern, add it to the
+            // selection.
+            for(size_t i = 0; i < itsInstrument.getStationCount(); ++i)
+            {
+                casa::String name(itsInstrument.stations[i].name);
+                if(name.matches(regex))
+                    selection.insert(i);
+            }
+        }
+
+        TableExprNodeSet selectionExpr;
+        for(set<size_t>::const_iterator it = selection.begin();
+            it != selection.end();
+            ++it)
+        {
+            selectionExpr.add(
+                TableExprNodeSetElem(static_cast<casa::Int>(*it)));
+        }
+
+        filter = filter && itsMS.col("ANTENNA1").in(selectionExpr)
+            && itsMS.col("ANTENNA2").in(selectionExpr);
+    }
+
+    if(selection.isSet(VisSelection::BASELINE_FILTER))
+    {
+        if(selection.getBaselineFilter() == VisSelection::AUTO)
+            filter = filter && (itsMS.col("ANTENNA1") == itsMS.col("ANTENNA2"));
+        else if(selection.getBaselineFilter() == VisSelection::CROSS)
+            filter = filter && (itsMS.col("ANTENNA1") != itsMS.col("ANTENNA2"));
+    }
+
+    if(selection.isSet(VisSelection::CORRELATIONS))
+    {
+        LOG_WARN_STR("Correlation selection not yet implemented; all available"
+            " correlations will be used.");
+    }
+
+    return filter;
+}
+
+
+// NOTE: Optimization opportunity: when reading all channels, do not use a
+// slicer at all.
+Slicer MeasurementAIPS::getCellSlicer(const VisSelection &selection) const
+{
+    // Construct slicer with default setting.
+    IPosition start(2, 0, 0);
+    size_t lastChannel = getChannelCount() - 1;
+    size_t lastCorrelation = getCorrelationCount() - 1;
+    IPosition end(2, lastCorrelation, lastChannel);
+
+    // Validate and set selection.
+    pair<size_t, size_t> range = selection.getChannelRange();
+    if(selection.isSet(VisSelection::CHANNEL_START))
+        start = IPosition(2, 0, range.first);
+
+    if(selection.isSet(VisSelection::CHANNEL_END))
+        if(range.second > lastChannel)
+            LOG_WARN("Invalid end channel specified; using last channel"
+                " instead.");
+        else
+            end = IPosition(2, lastCorrelation, range.second);
+
+    return Slicer(start, end, Slicer::endIsLast);
+}
+
+
+VisGrid MeasurementAIPS::getGrid(const casa::Table tab_selection,
+    const casa::Slicer slicer) const
+{
+    VisGrid grid;
+
+    IPosition shape = slicer.length();
+    size_t nCorrelations = shape[0];
+    size_t nChannels = shape[1];
+
+    // Extract time grid based on TIME column (mid-point of integration
+    // interval).
+    // TODO: Should use TIME_CENTROID here (centroid of exposure)?
+    // NOTE: UVW is given of the TIME_CENTROID, not for TIME!
+    // NOTE: TIME_CENTROID may be different for each baseline!
+    ROScalarColumn<Double> c_time(tab_selection, "TIME");
+    Vector<Double> time = c_time.getColumn();
+
+    // Find all unique timeslots.
+    Vector<uInt> timeIndex;
+    uInt nTimeslots = GenSortIndirect<double>::sort(timeIndex, time,
+        Sort::Ascending, Sort::InsSort + Sort::NoDuplicates);
+
+    // Find all unique baselines.
+    Block<String> sortColumns(2);
+    sortColumns[0] = "ANTENNA1";
+    sortColumns[1] = "ANTENNA2";
+    Table baselines = tab_selection.sort(sortColumns, Sort::Ascending,
+        Sort::QuickSort + Sort::NoDuplicates);
+    uInt nBaselines = baselines.nrow();
+
+    LOG_DEBUG_STR("Selection contains " << nBaselines << " baseline(s), "
+        << nTimeslots << " timeslot(s), " << nChannels << " channel(s), and "
+        << nCorrelations << " correlation(s).");
+
+    // Initialize baseline axis.
+    ROScalarColumn<Int> c_antenna1(baselines, "ANTENNA1");
+    ROScalarColumn<Int> c_antenna2(baselines, "ANTENNA2");
+    Vector<Int> antenna1 = c_antenna1.getColumn();
+    Vector<Int> antenna2 = c_antenna2.getColumn();
+    for(uInt i = 0; i < nBaselines; ++i)
+        grid.baselines.insert(baseline_t(antenna1[i], antenna2[i]));
+
+    // Initialize time axis.
+    ROScalarColumn<Double> c_interval(tab_selection, "INTERVAL");
+    Vector<Double> interval = c_interval.getColumn();
+
+    vector<double> times(nTimeslots + 1);
+    for(uInt i = 0; i < nTimeslots; ++i)
+        // Compute _lower border_ of each integration cell.
+        times[i] = time[timeIndex[i]] - interval[timeIndex[i]] / 2.0;
+
+    times[nTimeslots] = time[timeIndex[nTimeslots - 1]]
+        + interval[timeIndex[nTimeslots - 1]] / 2.0;
+
+    grid.time = cell_centered_axis<irregular_series>(irregular_series(times),
+        nTimeslots);
+
+    // Initialize frequency axis.
+    double lower = itsSpectrum.lower(slicer.start()[1]);
+    double upper = itsSpectrum.upper(slicer.end()[1]);
+    double delta = (upper - lower) / nChannels;
+    grid.freq = cell_centered_axis<regular_series>(regular_series(lower,
+        delta), nChannels);
+
+    // Initialize polarization axis.
+    for(size_t i = 0; i < itsCorrelationProducts.size(); ++i)
+        grid.polarizations.insert(itsCorrelationProducts[i]);
+
+    return grid;
+}
+
+
+VisData::Pointer MeasurementAIPS::allocate(const VisGrid &grid) const
+{
+    size_t nTimeslots = grid.time.size();
+    size_t nBaselines = grid.baselines.size();
+    size_t nChannels = grid.freq.size();
+    size_t nPolarizations = grid.polarizations.size();
+
+    LOG_DEBUG_STR("Allocate: " << nBaselines << " baseline(s), "
+        << nTimeslots << " timeslot(s), " << nChannels << " channel(s), and "
+        << nPolarizations << " polarization(s).");
+
+    VisData::Pointer buffer(new VisData(nTimeslots, nBaselines, nChannels,
+        nPolarizations));
+
+    // Initially flag all timeslots as UNAVAILABLE.
+    for(size_t i = 0; i < nBaselines; ++i)
+        for(size_t j = 0; j < nTimeslots; ++j)
+           buffer->tslot_flag[i][j] = VisData::UNAVAILABLE;
+
+    // Copy time and frequency axis.
+    buffer->time = grid.time;
+    buffer->freq = grid.freq;
+
+    size_t index;
+
+    // Initialize baseline index.
+    index = 0;
+    for(set<baseline_t>::const_iterator it = grid.baselines.begin();
+        it != grid.baselines.end();
+        ++it)
+    {
+        buffer->baselines[*it] = index;
+        ++index;
+    }
+
+    // Initialize polarizations index.
+    index = 0;
+    for(set<string>::const_iterator it = grid.polarizations.begin();
+        it != grid.polarizations.end();
+        ++it)
+    {
+        buffer->polarizations[*it] = index;
+        ++index;
+    }
+
+    return buffer;
+}
+
+
+} //# namespace BBS
+} //# namespace LOFAR
diff --git a/CEP/BB/BBSKernel/src/Model.cc b/CEP/BB/BBSKernel/src/Model.cc
new file mode 100644
index 0000000000000000000000000000000000000000..bebe238efcf8ed7097cc58344bfff0b0a0635496
--- /dev/null
+++ b/CEP/BB/BBSKernel/src/Model.cc
@@ -0,0 +1,529 @@
+//# Model.cc: 
+//#
+//# Copyright (C) 2007
+//# ASTRON (Netherlands Foundation for Research in Astronomy)
+//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//# This program 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 2 of the License, or
+//# (at your option) any later version.
+//#
+//# This program 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 this program; if not, write to the Free Software
+//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//# $Id$
+
+#include <lofar_config.h>
+#include <BBSKernel/Model.h>
+
+#include <BBSKernel/Measurement.h>
+
+#include <BBSKernel/MNS/MeqPhaseRef.h>
+#include <BBSKernel/MNS/MeqParmFunklet.h>
+#include <BBSKernel/MNS/MeqParmSingle.h>
+#include <BBSKernel/MNS/MeqDiag.h>
+#include <BBSKernel/MNS/MeqJonesInvert.h>
+#include <BBSKernel/MNS/MeqBaseDFTPS.h>
+#include <BBSKernel/MNS/MeqBaseLinPS.h>
+#include <BBSKernel/MNS/MeqJonesCMul3.h>
+#include <BBSKernel/MNS/MeqJonesSum.h>
+#include <BBSKernel/MNS/MeqJonesVisData.h>
+
+#include <BBSKernel/MNS/MeqStation.h>
+#include <BBSKernel/MNS/MeqStatUVW.h>
+#include <BBSKernel/MNS/MeqLMN.h>
+#include <BBSKernel/MNS/MeqDFTPS.h>
+#include <BBSKernel/MNS/MeqJonesNode.h>
+#include <BBSKernel/MNS/MeqRequest.h>
+#include <BBSKernel/MNS/MeqJonesExpr.h>
+
+#include <Common/LofarLogger.h>
+#include <Common/StreamUtil.h>
+#include <Common/lofar_string.h>
+#include <Common/lofar_vector.h>
+#include <Common/lofar_map.h>
+
+#include <measures/Measures/MDirection.h>
+#include <casa/Quanta/Quantum.h>
+#include <casa/Arrays/Vector.h>
+
+#include <ParmDB/ParmDB.h>
+
+namespace LOFAR
+{
+namespace BBS 
+{
+using LOFAR::ParmDB::ParmDB;
+using std::max;
+
+Model::Model(const Instrument &instrument, MeqParmGroup &parmGroup,
+    ParmDB *skyDBase, MeqPhaseRef *phaseRef)
+{
+    // Construct source list.
+    itsSourceList.reset(new MeqSourceList(*skyDBase, parmGroup));
+
+    // Make nodes for all stations.
+    makeStationNodes(instrument, *phaseRef);
+}
+
+
+void Model::makeEquations(EquationType type, const vector<string> &components,
+    const set<baseline_t> &baselines, const vector<string> &sources,
+    MeqParmGroup &parmGroup, ParmDB *instrumentDBase, MeqPhaseRef *phaseRef,
+    VisData::Pointer data)
+{
+    // Parse component names.
+    vector<bool> mask(N_ModelComponent, false);
+    for(vector<string>::const_iterator it = components.begin();
+        it != components.end();
+        ++it)
+    {
+        if(*it == "GAIN")
+            mask[GAIN] = true;
+        else if(*it == "DIRECTIONAL_GAIN")
+            mask[DIRECTIONAL_GAIN] = true;
+        else if(*it == "BANDPASS")
+            mask[BANDPASS] = true;
+        else if(*it == "PHASORS")
+            mask[PHASORS] = true;
+    }
+/*
+    if(mask{GAIN] && mask[DIRECTIONAL_GAIN])
+        LOG_WARN("Model components GAIN and DIRECTIONAL_GAIN are mutually"
+            " exclusive; using GAIN only.");
+*/
+
+    string part1("real:");
+    string part2("imag:");
+    if(mask[PHASORS])
+    {
+        part1 = "ampl:";
+        part2 = "phase:";
+    }
+
+    // Clear all equations.
+    itsEquations.clear();
+
+    // Make nodes for all specified sources (use all if none specified).
+    if(sources.empty())
+        makeSourceNodes(itsSourceList->getSourceNames(), phaseRef);
+    else
+        makeSourceNodes(sources, phaseRef);
+
+    // Make baseline equations.
+    size_t nStations = itsStationNodes.size();
+    size_t nSources = itsSourceNodes.size();
+
+    vector<MeqExpr> dft(nStations * nSources);
+    vector<MeqJonesExpr> gain, inv_gain, bandpass;
+
+    if(mask[BANDPASS])
+        bandpass.resize(nStations);
+
+    if(mask[GAIN] || mask[DIRECTIONAL_GAIN])
+    {
+        inv_gain.resize(nStations);
+        if(mask[GAIN])
+            gain.resize(nStations);
+        else
+            gain.resize(nStations * nSources);
+    }
+
+    for(size_t i = 0; i < nStations; ++i)
+    {
+        // Make a phase term per station per source.
+        for(size_t j = 0; j < nSources; ++j)
+            dft[i * nSources + j] = MeqExpr(new MeqDFTPS(itsLMNNodes[j],
+                itsUVWNodes[i].get()));
+
+        // Make a bandpass expression per station.
+        if(mask[BANDPASS])
+        {
+            string suffix = itsStationNodes[i]->getName();
+
+            MeqExpr B11(MeqParmFunklet::create("bandpass:11:" + suffix,
+                parmGroup, instrumentDBase));
+            MeqExpr B22(MeqParmFunklet::create("bandpass:22:" + suffix,
+                parmGroup, instrumentDBase));
+
+            bandpass[i] = new MeqDiag(MeqExpr(B11), MeqExpr(B22));
+        }
+
+        // Make a complex gain expression per station and possibly per source.
+        if(mask[GAIN])
+        {
+            MeqExprRep *J11, *J12, *J21, *J22;
+            string suffix = itsStationNodes[i]->getName();
+
+            // Make a J-jones expression per station
+            MeqExpr J11_part1(MeqParmFunklet::create("gain:11:" + part1
+                + suffix, parmGroup, instrumentDBase));
+            MeqExpr J11_part2(MeqParmFunklet::create("gain:11:" + part2
+                + suffix, parmGroup, instrumentDBase));
+            MeqExpr J12_part1(MeqParmFunklet::create("gain:12:" + part1
+                + suffix, parmGroup, instrumentDBase));
+            MeqExpr J12_part2(MeqParmFunklet::create("gain:12:" + part2
+                + suffix, parmGroup, instrumentDBase));
+            MeqExpr J21_part1(MeqParmFunklet::create("gain:21:" + part1
+                + suffix, parmGroup, instrumentDBase));
+            MeqExpr J21_part2(MeqParmFunklet::create("gain:21:" + part2
+                + suffix, parmGroup, instrumentDBase));
+            MeqExpr J22_part1(MeqParmFunklet::create("gain:22:" + part1
+                + suffix, parmGroup, instrumentDBase));
+            MeqExpr J22_part2(MeqParmFunklet::create("gain:22:" + part2
+                + suffix, parmGroup, instrumentDBase));
+
+            if(mask[PHASORS])
+            {
+                J11 = new MeqExprAPToComplex(J11_part1, J11_part2);
+                J12 = new MeqExprAPToComplex(J12_part1, J12_part2);
+                J21 = new MeqExprAPToComplex(J21_part1, J21_part2);
+                J22 = new MeqExprAPToComplex(J22_part1, J22_part2);
+            }
+            else
+            {
+                J11 = new MeqExprToComplex(J11_part1, J11_part2);
+                J12 = new MeqExprToComplex(J12_part1, J12_part2);
+                J21 = new MeqExprToComplex(J21_part1, J21_part2);
+                J22 = new MeqExprToComplex(J22_part1, J22_part2);
+            }
+
+            gain[i] = new MeqJonesNode(MeqExpr(J11), MeqExpr(J12),
+                MeqExpr(J21), MeqExpr(J22));
+            inv_gain[i] = new MeqJonesInvert(gain[i]);
+        }
+        else if(mask[DIRECTIONAL_GAIN])
+        {
+            // Make a J-jones expression per station per source. Eventually,
+            // patches of several sources will be supported as well.
+            for(size_t j = 0; j < nSources; ++j)
+            {
+                MeqExprRep *J11, *J12, *J21, *J22;
+                string suffix = itsStationNodes[i]->getName() + ":"
+                    + itsSourceNodes[j]->getName();
+
+                MeqExpr J11_part1(MeqParmFunklet::create("gain:11:" + part1
+                    + suffix, parmGroup, instrumentDBase));
+                MeqExpr J11_part2(MeqParmFunklet::create("gain:11:" + part2
+                    + suffix, parmGroup, instrumentDBase));
+                MeqExpr J12_part1(MeqParmFunklet::create("gain:12:" + part1
+                    + suffix, parmGroup, instrumentDBase));
+                MeqExpr J12_part2(MeqParmFunklet::create("gain:12:" + part2
+                    + suffix, parmGroup, instrumentDBase));
+                MeqExpr J21_part1(MeqParmFunklet::create("gain:21:" + part1
+                    + suffix, parmGroup, instrumentDBase));
+                MeqExpr J21_part2(MeqParmFunklet::create("gain:21:" + part2
+                    + suffix, parmGroup, instrumentDBase));
+                MeqExpr J22_part1(MeqParmFunklet::create("gain:22:" + part1
+                    + suffix, parmGroup, instrumentDBase));
+                MeqExpr J22_part2(MeqParmFunklet::create("gain:22:" + part2
+                    + suffix, parmGroup, instrumentDBase));
+
+                if(mask[PHASORS])
+                {
+                    J11 = new MeqExprAPToComplex(J11_part1, J11_part2);
+                    J12 = new MeqExprAPToComplex(J12_part1, J12_part2);
+                    J21 = new MeqExprAPToComplex(J21_part1, J21_part2);
+                    J22 = new MeqExprAPToComplex(J22_part1, J22_part2);
+                }
+                else
+                {
+                    J11 = new MeqExprToComplex(J11_part1, J11_part2);
+                    J12 = new MeqExprToComplex(J12_part1, J12_part2);
+                    J21 = new MeqExprToComplex(J21_part1, J21_part2);
+                    J22 = new MeqExprToComplex(J22_part1, J22_part2);
+                }
+
+                gain[i * nSources + j] = new MeqJonesNode(MeqExpr(J11),
+                    MeqExpr(J12), MeqExpr(J21), MeqExpr(J22));
+
+                // Gain correction is always performed with respect to the
+                // direction of the first source (patch).
+                if(j == 0)
+                    inv_gain[i] = new MeqJonesInvert(gain[i * nSources]);
+            }
+        }
+    }
+
+    if(type == CORRECT)
+    {
+        for(set<baseline_t>::const_iterator it = baselines.begin();
+            it != baselines.end();
+            ++it)
+        {
+            const baseline_t &baseline = *it;
+            itsEquations[baseline] = new MeqJonesCMul3(inv_gain[baseline.first],
+                    new MeqJonesVisData(data, baseline),
+                    inv_gain[baseline.second]);
+        }
+    }
+    else
+    {
+
+        for(set<baseline_t>::const_iterator it = baselines.begin();
+            it != baselines.end();
+            ++it)
+        {
+            const baseline_t &baseline = *it;
+
+            vector<MeqJonesExpr> terms;
+            for(size_t j = 0; j < nSources; ++j)
+            {
+                MeqExpr base
+                    (new MeqBaseDFTPS(dft[baseline.first * nSources + j],
+                    dft[baseline.second * nSources + j], itsLMNNodes[j]));
+
+                MeqPointSource *source =
+                    dynamic_cast<MeqPointSource*>(itsSourceNodes[j]);
+
+                MeqJonesExpr sourceTerm(new MeqBaseLinPS(base, source));
+
+                if(mask[DIRECTIONAL_GAIN])
+                {
+                    terms.push_back
+                        (new MeqJonesCMul3(gain[baseline.first * nSources + j],
+                        sourceTerm, gain[baseline.second * nSources + j]));
+                }
+                else
+                    terms.push_back(sourceTerm);
+            }
+
+            MeqJonesExpr sum;
+            if(terms.size() == 1)
+                sum = terms.front();
+            else
+                sum = MeqJonesExpr(new MeqJonesSum(terms));
+
+            if(mask[GAIN])
+            {
+                sum = new MeqJonesCMul3(gain[baseline.first], sum,
+                    gain[baseline.second]);
+            }
+
+            if(mask[BANDPASS])
+            {
+                sum = new MeqJonesCMul3(bandpass[baseline.first], sum,
+                    bandpass[baseline.second]);
+            }
+            itsEquations[baseline] = sum;
+        }
+    }
+}
+
+
+void Model::precalculate(const MeqRequest& request)
+{
+    if(itsEquations.empty())
+        return;
+
+    // First clear the levels of all nodes in the tree.
+    for(map<baseline_t, MeqJonesExpr>::iterator it = itsEquations.begin();
+        it != itsEquations.end();
+        ++it)
+    {
+        MeqJonesExpr &expr = it->second;
+        if(!expr.isNull())
+            expr.clearDone();
+    }
+
+    // Now set the levels of all nodes in the tree.
+    // The top nodes have level 0; lower nodes have 1, 2, etc..
+    int nrLev = -1;
+    for(map<baseline_t, MeqJonesExpr>::iterator it = itsEquations.begin();
+        it != itsEquations.end();
+        ++it)
+    {
+        MeqJonesExpr &expr = it->second;
+        if(!expr.isNull())
+            nrLev = max(nrLev, expr.setLevel(0));
+    }
+    nrLev++;
+    ASSERT(nrLev > 0);
+
+    // Find the nodes to be precalculated at each level.
+    // That is not needed for the root nodes (the baselines).
+    // The nodes used by the baselines are always precalculated (even if
+    // having one parent).
+    // It may happen that a station is used by only one baseline. Calculating
+    // such a baseline is much more work if the station was not precalculated.
+    vector<vector<MeqExprRep*> > precalcNodes(nrLev);
+    for(size_t level = 1; level < nrLev; ++level)
+    {
+        vector<MeqExprRep*> &nodes = precalcNodes[level];
+        nodes.resize(0);
+
+        for(map<baseline_t, MeqJonesExpr>::iterator it = itsEquations.begin();
+            it != itsEquations.end();
+            ++it)
+        {
+            MeqJonesExpr &expr = it->second;
+            if(!expr.isNull())
+                expr.getCachingNodes(nodes, level, false);
+        }
+    }
+
+/************ DEBUG DEBUG DEBUG ************/
+    LOG_TRACE_FLOW_STR("#levels=" << nrLev);
+    for(size_t i = 0; i < nrLev; ++i)
+    {
+        LOG_TRACE_FLOW_STR("#expr on level " << i << " is "
+            << precalcNodes[i].size());
+    }
+/************ DEBUG DEBUG DEBUG ************/
+
+#pragma omp parallel
+    {
+        // Loop through expressions to be precalculated.
+        // At each level the expressions can be executed in parallel.
+        // Level 0 is formed by itsExpr which are not calculated here.
+        for(size_t level = precalcNodes.size(); --level > 0;)
+        {
+            vector<MeqExprRep*> &nodes = precalcNodes[level];
+            if(!nodes.empty())
+#pragma omp for schedule(dynamic)
+                for(size_t i=0; i < nodes.size(); ++i)
+                    nodes[i]->precalculate(request);
+        }
+    } // omp parallel
+}
+
+
+MeqJonesResult Model::evaluate(baseline_t baseline, const MeqRequest& request)
+{
+    map<baseline_t, MeqJonesExpr>::iterator it =
+        itsEquations.find(baseline);
+    ASSERTSTR(it != itsEquations.end(), "Result requested for unknown"
+        " baseline " << baseline.first << " - " << baseline.second);
+
+    return it->second.getResult(request);
+}
+
+
+void Model::makeStationNodes(const Instrument &instrument,
+    const MeqPhaseRef &phaseRef)
+{
+    // Workaround to facilitate comparison with earlier versions of BBS
+    // and with MeqTree.
+    casa::Quantum<casa::Vector<casa::Double> > angles =
+        phaseRef.direction().getAngle();
+    casa::MDirection phaseRef2(casa::MVDirection(angles.getBaseValue()(0),
+        angles.getBaseValue()(1)), casa::MDirection::J2000);
+    LOG_WARN_STR("Superfluous conversion of phase center from/to"
+        " casa::MDirection to allow comparison with earlier version of BBS and"
+        " with MeqTree. Should be removed after validation.");
+
+    itsStationNodes.resize(instrument.getStationCount());
+    itsUVWNodes.resize(instrument.getStationCount());
+    for(size_t i = 0; i < instrument.getStationCount(); ++i)
+    {
+        const casa::MVPosition &position =
+            instrument.stations[i].position.getValue();
+
+        MeqParmSingle *x = new MeqParmSingle("position:x:" +
+            instrument.stations[i].name, position(0));
+        MeqParmSingle *y = new MeqParmSingle("position:y:" +
+            instrument.stations[i].name, position(1));
+        MeqParmSingle *z = new MeqParmSingle("position:z:" +
+            instrument.stations[i].name, position(2));
+
+        itsStationNodes[i].reset(new MeqStation(x, y, z,
+            instrument.stations[i].name));
+
+        itsUVWNodes[i].reset(new MeqStatUVW(itsStationNodes[i].get(),
+            phaseRef2, instrument.position));
+    }
+}
+
+
+void Model::makeSourceNodes(const vector<string> &names, MeqPhaseRef *phaseRef)
+{
+    itsSourceNodes.resize(names.size());
+    itsLMNNodes.resize(names.size());
+    for(size_t i = 0; i < names.size(); ++i)
+    {
+        MeqSource *source = itsSourceList->getSource(names[i]);
+        itsSourceNodes[i] = source;
+
+        // Create an LMN node for the source.
+        itsLMNNodes[i] = new MeqLMN(source);
+        itsLMNNodes[i]->setPhaseRef(phaseRef);
+    }
+}
+
+
+void Model::setStationUVW(const Instrument &instrument, VisData::Pointer data)
+{
+    size_t nStations = instrument.getStationCount();
+    vector<bool> statDone(nStations);
+    vector<double> statUVW(3 * nStations);
+
+    // Step through the MS by timeslot.
+    for (size_t tslot = 0; tslot < data->time.size(); ++tslot)
+    {
+        double time = data->time(tslot);
+        fill(statDone.begin(), statDone.end(), false);
+
+        // Set UVW of first station used to 0 (UVW coordinates are relative!).
+        size_t station0 = data->baselines.begin()->first.first;
+        statUVW[3 * station0] = 0.0;
+        statUVW[3 * station0 + 1] = 0.0;
+        statUVW[3 * station0 + 2] = 0.0;
+        itsUVWNodes[station0]->set(time, 0.0, 0.0, 0.0);
+        statDone[station0] = true;
+
+        size_t nDone;
+        do
+        {
+            nDone = 0;
+            for (map<baseline_t, size_t>::const_iterator it =
+                    data->baselines.begin();
+                it != data->baselines.end();
+                ++it)
+            {
+                size_t blindex = it->second;
+                if(data->tslot_flag[blindex][tslot])
+                    continue;
+
+                size_t statA = it->first.first;
+                size_t statB = it->first.second;
+                if (statDone[statA] && !statDone[statB])
+                {
+                    statUVW[3 * statB] =
+                        data->uvw[blindex][tslot][0] - statUVW[3 * statA];
+                    statUVW[3 * statB + 1] =
+                        data->uvw[blindex][tslot][1] - statUVW[3 * statA + 1];
+                    statUVW[3 * statB + 2] =
+                        data->uvw[blindex][tslot][2] - statUVW[3 * statA + 2];
+                    statDone[statB] = true;
+                    itsUVWNodes[statB]->set(time, statUVW[3 * statB],
+                        statUVW[3 * statB + 1], statUVW[3 * statB + 2]);
+                    ++nDone;
+                }
+                else if (statDone[statB] && !statDone[statA])
+                {
+                    statUVW[3 * statA] =
+                        statUVW[3 * statB] - data->uvw[blindex][tslot][0];
+                    statUVW[3 * statA + 1] =
+                        statUVW[3 * statB + 1] - data->uvw[blindex][tslot][1];
+                    statUVW[3 * statA + 2] =
+                        statUVW[3 * statB + 2] - data->uvw[blindex][tslot][2];
+                    statDone[statA] = true;
+                    itsUVWNodes[statA]->set(time, statUVW[3 * statA],
+                        statUVW[3 * statA + 1], statUVW[3 * statA + 2]);
+                    ++nDone;
+                }
+            }
+        }
+        while(nDone > 0);
+    }
+}
+
+} //# namespace BBS
+} //# namespace LOFAR
diff --git a/CEP/BB/BBSKernel/src/Prediffer.cc b/CEP/BB/BBSKernel/src/Prediffer.cc
index f0d01da2c4d30e3f7a173b7da63e88b885463256..db7d4c180b7ffb5f03add9acb725b6df26ebe542 100644
--- a/CEP/BB/BBSKernel/src/Prediffer.cc
+++ b/CEP/BB/BBSKernel/src/Prediffer.cc
@@ -23,135 +23,68 @@
 #include <lofar_config.h>
 
 #include <BBSKernel/Prediffer.h>
-#include <BBSKernel/MMap.h>
-#include <BBSKernel/FlagsMap.h>
+#include <BBSKernel/MeasurementAIPS.h>
 #include <BBSKernel/Exceptions.h>
-#include <BBSKernel/MNS/MeqLMN.h>
-#include <BBSKernel/MNS/MeqDFTPS.h>
-#include <BBSKernel/MNS/MeqDiag.h>
-#include <BBSKernel/MNS/MeqBaseDFTPS.h>
-#include <BBSKernel/MNS/MeqBaseLinPS.h>
-#include <BBSKernel/MNS/MeqStatExpr.h>
-#include <BBSKernel/MNS/MeqJonesSum.h>
-#include <BBSKernel/MNS/MeqMatrixTmp.h>
-#include <BBSKernel/MNS/MeqMatrixComplexArr.h>
+
+#include <BBSKernel/MNS/MeqDomain.h>
+#include <BBSKernel/MNS/MeqRequest.h>
+#include <BBSKernel/MNS/MeqResult.h>
+#include <BBSKernel/MNS/MeqJonesResult.h>
+
+#include <BBSKernel/MNS/MeqMatrix.h>
 #include <BBSKernel/MNS/MeqMatrixRealArr.h>
-#include <BBSKernel/MNS/MeqParmFunklet.h>
-#include <BBSKernel/MNS/MeqParmSingle.h>
-#include <BBSKernel/MNS/MeqPointSource.h>
-#include <BBSKernel/MNS/MeqJonesCMul3.h>
-#include <BBSKernel/MNS/MeqJonesInvert.h>
-#include <BBSKernel/MNS/MeqJonesMMap.h>
+#include <BBSKernel/MNS/MeqMatrixComplexArr.h>
+
+#include <BBSKernel/MNS/MeqParm.h>
+#include <BBSKernel/MNS/MeqFunklet.h>
+#include <BBSKernel/MNS/MeqPhaseRef.h>
 
 #include <Common/Timer.h>
 #include <Common/LofarLogger.h>
-#include <Blob/BlobIStream.h>
-#include <Blob/BlobIBufStream.h>
-#include <Blob/BlobArray.h>
 #include <Common/StreamUtil.h>
 #include <Common/DataConvert.h>
-#include <Common/LofarLogger.h>
+#include <Common/lofar_algorithm.h>
+#include <Common/lofar_fstream.h>
+#include <Common/lofar_iostream.h>
+#include <Common/lofar_iomanip.h>
 
-#include <casa/Arrays/ArrayIO.h>
-#include <casa/Arrays/ArrayMath.h>
-#include <casa/Arrays/ArrayLogical.h>
-#include <casa/Arrays/Matrix.h>
-#include <casa/Arrays/Slice.h>
-#include <casa/Arrays/Slicer.h>
-#include <casa/Arrays/Vector.h>
-// Vector2.cc: necessary to instantiate .tovector()
-#ifdef AIPS_NO_TEMPLATE_SRC
-#include <casa/Arrays/Vector2.cc>
-#endif
-#include <casa/Quanta/MVBaseline.h>
-#include <casa/Quanta/MVPosition.h>
-#include <casa/OS/Timer.h>
-#include <casa/OS/RegularFile.h>
-//#include <casa/OS/SymLink.h>
-#include <casa/Containers/Record.h>
-#include <casa/IO/AipsIO.h>
-#include <casa/IO/MemoryIO.h>
 #include <casa/Exceptions/Error.h>
 #include <casa/Utilities/Regex.h>
 #include <casa/Utilities/GenSort.h>
+#include <casa/Quanta/MVTime.h>
+#include <scimath/Fitting/LSQFit.h>
 
-#include <measures/Measures/MeasConvert.h>
-#include <measures/Measures/MeasTable.h>
-#include <measures/Measures/MPosition.h>
-#include <measures/Measures/MDirection.h>
-#include <measures/Measures/Stokes.h>
-
-#include <tables/Tables/Table.h>
-#include <tables/Tables/TableDesc.h>
-#include <tables/Tables/ScalarColumn.h>
-#include <tables/Tables/ArrColDesc.h>
-#include <tables/Tables/TiledColumnStMan.h>
-
-#include <ms/MeasurementSets/MeasurementSet.h>
-#include <ms/MeasurementSets/MSAntenna.h>
-#include <ms/MeasurementSets/MSAntennaColumns.h>
-#include <ms/MeasurementSets/MSDataDescription.h>
-#include <ms/MeasurementSets/MSDataDescColumns.h>
-#include <ms/MeasurementSets/MSField.h>
-#include <ms/MeasurementSets/MSFieldColumns.h>
-#include <ms/MeasurementSets/MSObservation.h>
-#include <ms/MeasurementSets/MSObsColumns.h>
-#include <ms/MeasurementSets/MSPolarization.h>
-#include <ms/MeasurementSets/MSPolColumns.h>
-#include <ms/MeasurementSets/MSSpectralWindow.h>
-#include <ms/MeasurementSets/MSSpWindowColumns.h>
+#include <measures/Measures.h>
 
+#include <functional>
 #include <stdexcept>
-#include <iostream>
-#include <iomanip>
-#include <fstream>
-//#include <malloc.h>
-#include <unistd.h>
-#include <algorithm>
-
-//#include <BBSKernel/BBSTestLogger.h>
 
 #if defined _OPENMP
 #include <omp.h>
 #endif
 
-using namespace casa;
-using namespace std;
+#ifdef EXPR_GRAPH
+#include <BBSKernel/MNS/MeqJonesExpr.h>
+#endif
 
 namespace LOFAR
 {
-namespace BBS 
+namespace BBS
 {
 using LOFAR::operator<<;
-using std::max;
-
-Prediffer::Prediffer(   const string &measurementSet,
-                        const string &inputColumn,
-                        const string &skyParameterDB,
-                        const string &instrumentParameterDB,
-                        const string &historyDB,
-                        uint subbandID,
-                        bool calcUVW)
-    :   itsSubbandID        (subbandID),
-        itsCalcUVW          (calcUVW),
-        itsMEP              (0),
-        itsGSMMEP           (0),
-        itsHistoryDB        (0),
-        itsSources          (0),
-        itsInDataColumn     (inputColumn),
-        itsNrPert           (0),
-        itsNCorr            (0),
-        itsNrBl             (0),
-        itsTimeIndex        (0),
-        itsNrTimes          (0),
-        itsNrTimesDone      (0),
-        itsInDataMap        (0),
-        itsOutDataMap       (0),
-        itsFlagsMap         (0),
-        itsWeightMap        (0),
-        itsIsWeightSpec     (false)
+using LOFAR::ParmDB::ParmDB;
+using LOFAR::ParmDB::ParmDBMeta;
+
+Prediffer::Prediffer(const string &measurement, size_t subband,
+    const string &inputColumn, const string &skyDBase,
+    const string &instrumentDBase, const string &historyDBase, bool readUVW)
+    :   itsSubband              (subband),
+        itsInputColumn          (inputColumn),
+        itsReadUVW              (readUVW),
+        itsChunkSize            (0),
+        itsChunkPosition        (0)
 {
-    LOG_INFO("Prediffer was compiled with the following options:");
+    LOG_INFO("Compile time options:");
 
 #ifdef _OPENMP
     LOG_INFO("  _OPENMP: yes");
@@ -164,76 +97,86 @@ Prediffer::Prediffer(   const string &measurementSet,
 #else
     LOG_INFO("  EXPR_GRAPH: no");
 #endif
-    
+
 #ifdef COMPUTE_SQUARED_ERROR
     LOG_INFO("  COMPUTE_SQUARED_ERROR: yes");
 #else
     LOG_INFO("  COMPUTE_SQUARED_ERROR: no");
 #endif
-    
-    // Get path to measurement set.
-    itsMSName = Path(measurementSet).absoluteName();
-    LOG_INFO_STR("Input: " << itsMSName << "::" << itsInDataColumn);
-    
-    // Read meta data (needed to know for instance the number of available
-    // correlations).
+
+    // Open measurement.
     try
     {
-        readMeasurementSetMetaData(itsMSName);
+        LOG_INFO_STR("Input: " << measurement << "::" << itsInputColumn);
+        itsMeasurement.reset(new MeasurementAIPS(measurement, 0, subband, 0));
     }
-    catch (AipsError &_ex)
+    catch(casa::AipsError &_ex)
     {
-        THROW(BBSKernelException, "Failed to read input meta data (AipsError: " << _ex.what() << ")");
+        THROW(BBSKernelException, "Failed to open measurement: "
+            << measurement << endl << "(AipsError: "
+            << _ex.what() << ")");
     }
-    
-    // Amongst other things, processMSDesc() calls fillStations(), which
-    // sets itsStations. Eventually it may make sense to remove MSDesc from
-    // the Prediffer.
-    processMSDesc(itsSubbandID);
-    
-    // Open sky parmdb.
+
+    // Open sky model parmdb.
     try
     {
-        LOFAR::ParmDB::ParmDBMeta skyParameterDBMeta("aips", skyParameterDB);
-        itsGSMMEP = new LOFAR::ParmDB::ParmDB(skyParameterDBMeta);
-        itsGSMMEPName = skyParameterDBMeta.getTableName();
-        LOG_INFO_STR("Sky model ParmDB: " << itsGSMMEPName);
+        ParmDBMeta skyDBaseMeta("aips", skyDBase);
+        LOG_INFO_STR("Sky model database: " << skyDBaseMeta.getTableName());
+        itsSkyDBase.reset(new ParmDB(skyDBaseMeta));
     }
-    catch (AipsError &_ex)
+    catch(casa::AipsError &_ex)
     {
-        THROW(BBSKernelException, "Failed to open sky parameter db: " << skyParameterDB << endl << "(AipsError: " << _ex.what() << ")");
+        THROW(BBSKernelException, "Failed to open sky parameter db: "
+            << skyDBase << endl << "(AipsError: " << _ex.what() << ")");
     }
 
-    // Open instrument parmdb.
+    // Open instrument model parmdb.
     try
     {
-        LOFAR::ParmDB::ParmDBMeta instrumentParameterDBMeta("aips", instrumentParameterDB);
-        itsMEP = new LOFAR::ParmDB::ParmDB(instrumentParameterDBMeta);
-        itsMEPName = instrumentParameterDBMeta.getTableName();
-        LOG_INFO_STR("Instrument model ParmDB: " << itsMEPName);
+        ParmDBMeta instrumentDBaseMeta("aips", instrumentDBase);
+        LOG_INFO_STR("Instrument model database: "
+            << instrumentDBaseMeta.getTableName());
+        itsInstrumentDBase.reset(new ParmDB(instrumentDBaseMeta));
     }
-    catch (AipsError &_ex)
+    catch(casa::AipsError &_ex)
     {
-        THROW(BBSKernelException, "Failed to open instrument parameter db: " << instrumentParameterDB << endl << "(AipsError: " << _ex.what() << ")");
+        THROW(BBSKernelException, "Failed to open instrument parameter db: "
+            << instrumentDBase << endl << "(AipsError: " << _ex.what() << ")");
     }
-    
+
     // Open history db.
-    if(!historyDB.empty())
+    if(!historyDBase.empty())
     {
         try
         {
-            LOFAR::ParmDB::ParmDBMeta historyDBMeta("aips", historyDB);
-            itsHistoryDB = new LOFAR::ParmDB::ParmDB(historyDBMeta);
-            LOG_INFO_STR("History DB: " << historyDBMeta.getTableName());
+            ParmDBMeta historyDBaseMeta("aips", historyDBase);
+            LOG_INFO_STR("History DB: " << historyDBaseMeta.getTableName());
+            itsHistoryDBase.reset(new ParmDB(historyDBaseMeta));
         }
-        catch (AipsError &_ex)
+        catch (casa::AipsError &_ex)
         {
-            THROW(BBSKernelException, "Failed to open history db: " << historyDB << endl << "(AipsError: " << _ex.what() << ")");
+            THROW(BBSKernelException, "Failed to open history db: "
+                << historyDBase << endl << "(AipsError: " << _ex.what() << ")");
         }
     }
     else
         LOG_INFO_STR("History DB: -");
 
+    LOG_INFO_STR("UVW source: " << (readUVW ? "read" : "computed"));
+    LOG_INFO_STR("UVW convention: " << (readUVW ? "as recorded in the input"
+        " measurement" : "ANTENNA2 - ANTENNA1 (AIPS++ convention)"));
+//    ASSERTSTR(computeUVW, "Reading of UVW coordinates from the input"
+//        " measurement temporarily disabled.");
+
+    // Initialize model.
+    casa::MEpoch startTimeMeas = itsMeasurement->getTimeRange().first;
+    casa::Quantum<casa::Double> startTime = startTimeMeas.get("s");
+    itsPhaseRef = MeqPhaseRef(itsMeasurement->getPhaseCenter(),
+        startTime.getValue("s"));
+
+    itsModel.reset(new Model(itsMeasurement->getInstrument(), itsParmGroup,
+        itsSkyDBase.get(), &itsPhaseRef));
+
     // Allocate thread private buffers.
 #if defined _OPENMP
     itsNthread = omp_get_max_threads();
@@ -251,266 +194,231 @@ Prediffer::~Prediffer()
 {
   LOG_TRACE_FLOW( "Prediffer destructor" );
 
-  delete itsSources;
-  for (vector<MeqStatUVW*>::iterator iter = itsStatUVW.begin();
-       iter != itsStatUVW.end();
-       iter++) {
-    delete *iter;
-  }
-  for (vector<MeqStation*>::iterator iter = itsStations.begin();
-       iter != itsStations.end();
-       iter++) {
-    delete *iter;
-  }
-
-  delete itsMEP;
-  delete itsGSMMEP;
-//  delete itsHistoryDB;
-  
-  delete itsInDataMap;
-  delete itsOutDataMap;
-  delete itsFlagsMap;
-  delete itsWeightMap;
-
   // clear up the matrix pool
   MeqMatrixComplexArr::poolDeactivate();
   MeqMatrixRealArr::poolDeactivate();
 }
 
 
-void Prediffer::updateCorrelationMask(vector<bool> &mask, const vector<string> &requestedCorrelations)
+void Prediffer::setSelection(VisSelection selection)
 {
-    if(requestedCorrelations.empty()) return;
-    
-    const vector<string> &availableCorrelations = itsMSDesc.corrTypes;
-    for(int i = 0; i < availableCorrelations.size(); ++i)
-    {
-        if(mask[i])
-        {
-            mask[i] = false;
-            for(int j = 0; j < requestedCorrelations.size(); ++j)
-            {
-                if(requestedCorrelations[j] == availableCorrelations[i])
-                {
-                    mask[i] = true;
-                    break;
-                }
-            }
-        }
-    }
+    itsChunkSelection = selection;
+    itsGrid = itsMeasurement->grid(selection);
 }
 
 
-bool Prediffer::setSelection(const vector<string> &stations, const Correlation &correlation)
-{    
-    // Select correlations.
-    const vector<string> &availableCorrelations = itsMSDesc.corrTypes;
-    const vector<string> &requestedCorrelations = correlation.type;
-    LOG_INFO_STR("Available correlation(s): " << availableCorrelations);
-    LOG_INFO_STR("Requested correlation(s): " << requestedCorrelations);
-    
-    // Initially select all correlations.
-    fill(itsSelectedCorr.begin(), itsSelectedCorr.end(), true);
-    
-    // Deselect all correlations _not_ present in requestedCorrelations.
-    updateCorrelationMask(itsSelectedCorr, requestedCorrelations);
-    
-    // Verify that at least one correlations is still selected.
-    if(count(itsSelectedCorr.begin(), itsSelectedCorr.end(), true) == 0)
-    {
-        LOG_ERROR("At least one correlation should be selected.");
+void Prediffer::setChunkSize(size_t size)
+{
+    itsChunkSize = size;
+    itsChunkPosition = 0;
+}
+
+
+bool Prediffer::nextChunk()
+{
+    // Exit if the MS has no overlap in frequency with the specified work
+    // domain.
+//    if(startChannel >= itsMeasurement->getChannelCount())
+//        return false;
+    ASSERT(itsChunkPosition <= itsGrid.time.size());
+
+    if(itsChunkPosition == itsGrid.time.size())
         return false;
-    }
-    
-    // Output selected correlations (inform the user).
-    ostringstream os;
-    os << "Selected correlation(s):";
-    for(unsigned int i = 0; i < availableCorrelations.size(); ++i)
-    {
-        if(itsSelectedCorr[i])
-        {
-            os << " " << availableCorrelations[i];
-        }
-    }
-    LOG_INFO_STR(os.str());
-        
-    // Select stations.
-    const vector<string> &availableStations = itsMSDesc.antNames;
-    const vector<string> &requestedStations = stations;
-    LOG_INFO_STR("Available station(s): " << availableStations);
-    LOG_INFO_STR("Requested station(s): " << requestedStations);
-    
-    vector<string> debugSelectedStations;
-    if(requestedStations.empty())
+
+    // Clear time selection.
+    itsChunkSelection.clear(VisSelection::TIME_START);
+    itsChunkSelection.clear(VisSelection::TIME_END);
+
+    if(itsChunkSize == 0)
     {
-        // Select all available stations if none are requested explicitly.
-        itsSelStations = itsStations;
-        debugSelectedStations = availableStations;
+        itsChunkPosition = itsGrid.time.size();
     }
     else
     {
-        itsSelStations = vector<MeqStation*>(availableStations.size(), (MeqStation*) 0);
-        
-        for(vector<string>::const_iterator it = requestedStations.begin();
-            it != requestedStations.end();
-            ++it)
-        {
-            casa::Regex regex = casa::Regex::fromPattern(*it);
-            
-            // If a names matches, add its antennanr to the vector.
-            for(uint i = 0; i < availableStations.size(); ++i)
-            {
-                String stationName(availableStations[i]);
-                if(stationName.matches(regex))
-                {
-                    itsSelStations[i] = itsStations[i];
-                    debugSelectedStations.push_back(availableStations[i]);
-                }
-            }
-        }
-    }
-    LOG_INFO_STR("Selected station(s): " << debugSelectedStations);
-    
-    // Select baselines.
-    LOG_INFO_STR("Requested baselines: " << correlation.selection);
-    
-    itsSelectedBaselines.clear();    
-    for(int i = 0; i < itsMSDesc.ant1.size(); ++i)
-    {
-        const pair<int, int> baseline(itsMSDesc.ant1[i], itsMSDesc.ant2[i]);
-        
-        if(itsSelStations[baseline.first] && itsSelStations[baseline.second])
+        double start = itsGrid.time.lower(itsChunkPosition);
+        itsChunkPosition += itsChunkSize;
+        if(itsChunkPosition > itsGrid.time.size())
         {
-            if( correlation.selection == "ALL"
-                || (baseline.first == baseline.second && correlation.selection == "AUTO")
-                || (baseline.first != baseline.second && correlation.selection == "CROSS"))
-            {
-                itsSelectedBaselines[baseline] = i;
-            }
+            itsChunkPosition = itsGrid.time.size();
         }
-    }
-    LOG_INFO_STR("No. of selected baselines: " << itsSelectedBaselines.size());
-        
-    // Map flags into memory.
-    string flagFile = getFileForColumn(MS::columnName(MS::FLAG));
-    if(flagFile.empty())
-    {
-        return false;
-    }
-    LOG_INFO_STR("Input column " << MS::columnName(MS::FLAG) << " maps to: " << flagFile);
-    itsFlagsMap = new FlagsMap(flagFile, MMap::Read);
-    
-    // Get all sources from the ParmDB.
-    itsSources = new MeqSourceList(*itsGSMMEP, itsParmGroup);
-    
-    // Create the UVW nodes and fill them with uvw-s from MS if not calculated.
-    fillUVW();
-  
-    return (itsSelectedBaselines.size() > 0);
+        double end = itsGrid.time.upper(itsChunkPosition - 1);
+        itsChunkSelection.setTimeRange(start, end);
+    }
+
+    // Read data.
+    LOG_DEBUG("Reading chunk...");
+    itsChunkData = itsMeasurement->read(itsChunkSelection, itsInputColumn,
+        itsReadUVW);
+    if(itsReadUVW)
+        itsModel->setStationUVW(itsMeasurement->getInstrument(), itsChunkData);
+
+/*
+    LOG_DEBUG_STR("Times:");
+    for(size_t i = 0; i < itsChunkData->time.size(); ++i)
+        LOG_DEBUG_STR("i: " << i << " " << setprecision(15) <<
+        itsChunkData->time(i));
+*/
+
+    // Set work domain.
+    pair<double, double> freqRange = itsChunkData->freq.range();
+    pair<double, double> timeRange = itsChunkData->time.range();
+    itsWorkDomain = MeqDomain(freqRange.first, freqRange.second,
+        timeRange.first, timeRange.second);
+
+    // Read all parameter values that are part of the work domain.
+    readParms();
+
+    // Display chunk meta data.
+    LOG_INFO_STR("Chunk: ");
+    LOG_INFO_STR("  Frequency: "
+        << setprecision(3) << freqRange.first / 1000.0 << " kHz"
+        << " - "
+        << setprecision(3) << freqRange.second / 1000.0 << " kHz");
+    LOG_INFO_STR("  Bandwidth: "
+        << setprecision(3) << (freqRange.second - freqRange.first) / 1000.0
+        << "kHz (" << itsChunkData->freq.size() << " channels of "
+        << setprecision(3)
+        << (freqRange.second - freqRange.first) / itsChunkData->freq.size()
+        << " Hz)");
+    LOG_INFO_STR("  Time:      "
+        << casa::MVTime::Format(casa::MVTime::YMD, 6)
+        << casa::MVTime(casa::Quantum<casa::Double>(timeRange.first, "s"))
+        << " - "
+        << casa::MVTime::Format(casa::MVTime::YMD, 6)
+        << casa::MVTime(casa::Quantum<casa::Double>(timeRange.second, "s")));
+    LOG_INFO_STR("  Duration:  "
+        << setprecision(3) << (timeRange.second - timeRange.first) / 3600.0
+        << " hours (" << itsChunkData->time.size() << " samples of "
+        << setprecision(3)
+        << (timeRange.second - timeRange.first) / itsChunkData->time.size()
+        << " s on average)");
+
+    return true;
 }
 
 
 bool Prediffer::setContext(const Context &context)
 {
-    // Select correlations.
-    const vector<string> &availableCorrelations = itsMSDesc.corrTypes;
-    const vector<string> &requestedCorrelations = context.correlation.type;
-//    LOG_INFO_STR("Available correlation(s): " << availableCorrelations);
-    LOG_INFO_STR("Requested correlation(s): " << requestedCorrelations);
-    
-    
-    // Deselect all correlations _not_ present in requestedCorrelations.
-    itsCorr = itsSelectedCorr;
-    updateCorrelationMask(itsCorr, requestedCorrelations);
-    
-    // Verify that at least one correlations is still selected.
-    if(count(itsCorr.begin(), itsCorr.end(), true) == 0)
-    {
-        LOG_ERROR("At least one correlation should be selected.");
-        return false;
-    }
-    
-    // Output selected correlations (inform the user).
-    ostringstream os;
-    os << "Selected correlations(s):";
-    for(unsigned int i = 0; i < availableCorrelations.size(); ++i)
+    // Clear context.
+    itsContext = ProcessingContext();
+
+    // Select polarizations.
+    vector<string> requested;
+    if(context.correlation.type.empty())
+        requested = itsMeasurement->getCorrelations();
+    else
+        requested = context.correlation.type;
+
+    for(vector<string>::const_iterator it = requested.begin();
+        it != requested.end();
+        ++it)
     {
-        if(itsCorr[i])
+        size_t idx;
+
+        try
+        {
+            idx = itsChunkData->getPolarizationIndex(*it);
+            if(*it == "XX" || *it == "LL")
+                itsContext.polarizations.insert(make_pair(idx, 0));
+            else if(*it == "XY" || *it == "LR")
+                itsContext.polarizations.insert(make_pair(idx, 1));
+            else if(*it == "YX" || *it == "RL")
+                itsContext.polarizations.insert(make_pair(idx, 2));
+            else if(*it == "YY" || *it == "RR")
+                itsContext.polarizations.insert(make_pair(idx, 3));
+            else
+                LOG_WARN_STR("Don't know how to process polarization " << *it
+                    << "; skipping");
+        }
+        catch(BBSKernelException &ex)
         {
-            os << " " << availableCorrelations[i];
         }
     }
-    LOG_INFO_STR(os.str());
-    
+
+    // Verify that at least one polarization is selected.
+    if(itsContext.polarizations.empty())
+    {
+        LOG_ERROR("At least one polarization should be selected.");
+        return false;
+    }
+
     // Select baselines.
-    itsBLInx.clear();
     if(context.baselines.station1.empty())
     {
-        // If no baselines are speficied, use all baselines selected in the strategy that
-        // match the correlation selection of this context.
-        map<pair<int, int>, int>::const_iterator it = itsSelectedBaselines.begin();
-        while(it != itsSelectedBaselines.end())
+        // If no baselines are speficied, use all baselines selected in the
+        // strategy that match the correlation selection of this context.
+        map<baseline_t, size_t>::const_iterator it =
+            itsChunkData->baselines.begin();
+
+        while(it != itsChunkData->baselines.end())
         {
-            const pair<int, int> &baseline = it->first;
-            
-            if( context.correlation.selection == "ALL"
-                || (baseline.first == baseline.second && context.correlation.selection == "AUTO")
-                || (baseline.first != baseline.second && context.correlation.selection == "CROSS"))
+            const baseline_t &baseline = it->first;
+
+            if(context.correlation.selection == "ALL"
+                || (baseline.first == baseline.second
+                    && context.correlation.selection == "AUTO")
+                || (baseline.first != baseline.second
+                    && context.correlation.selection == "CROSS"))
             {
-                itsBLInx.push_back(it->second);
+                itsContext.baselines.insert(it->first);
             }
             ++it;
         }
     }
     else
     {
-        vector<string>::const_iterator baseline_it1 = context.baselines.station1.begin();
-        vector<string>::const_iterator baseline_it2 = context.baselines.station2.begin();
+        const Instrument &instrument = itsMeasurement->getInstrument();
+
+        vector<string>::const_iterator baseline_it1 =
+            context.baselines.station1.begin();
+        vector<string>::const_iterator baseline_it2 =
+            context.baselines.station2.begin();
 
         while(baseline_it1 != context.baselines.station1.end())
-        {   
-            // Find the IDs of all the stations of which the name matches the regex
-            // specified in the context (Baselines.station1 and Baselines.station2).
-            vector<int> stationGroup1, stationGroup2;
+        {
+            // Find the indices of all the stations of which the name matches
+            // the regex specified in the context.
+            set<size_t> stationGroup1, stationGroup2;
             casa::Regex regex1 = casa::Regex::fromPattern(*baseline_it1);
             casa::Regex regex2 = casa::Regex::fromPattern(*baseline_it2);
 
-            for(int i = 0; i < itsMSDesc.antNames.size(); ++i)
+            for(size_t i = 0; i < instrument.getStationCount(); ++i)
             {
-                String stationName(itsMSDesc.antNames[i]);
+                casa::String stationName(instrument.stations[i].name);
 
                 if(stationName.matches(regex1))
                 {
-                    stationGroup1.push_back(i);
+                    stationGroup1.insert(i);
                 }
 
                 if(stationName.matches(regex2))
                 {
-                    stationGroup2.push_back(i);
+                    stationGroup2.insert(i);
                 }
             }
 
-            LOG_WARN_STR("Baseline specification " << *baseline_it1 << ", " << *baseline_it2 << " does not match any baseline in the measurement set.");
-
-            // Generate all possible baselines (pairs) from the two groups of station IDs. If a baseline
-            // is selected in the current strategy _and_ matches the correlation selection of this context,
-            // select it for processing (by adding the ID of the _baseline_ to the itsBLInx vector).
-            for(vector<int>::const_iterator it1 = stationGroup1.begin(); it1 != stationGroup1.end(); ++it1)
+            // Generate all possible baselines (pairs) from the two groups of
+            // station indices. If a baseline is selected in the current
+            // strategy _and_ matches the correlation selection of this context,
+            // select it for processing.
+            for(set<size_t>::const_iterator it1 = stationGroup1.begin();
+                it1 != stationGroup1.end();
+                ++it1)
             {
-                for(vector<int>::const_iterator it2 = stationGroup2.begin(); it2 != stationGroup2.end(); ++it2)
+                for(set<size_t>::const_iterator it2 = stationGroup2.begin();
+                it2 != stationGroup2.end();
+                ++it2)
                 {
-                    if( context.correlation.selection == "ALL"
-                        || (*it1 == *it2 && context.correlation.selection == "AUTO")
-                        || (*it1 != *it2 && context.correlation.selection == "CROSS"))
+                    if(context.correlation.selection == "ALL"
+                        || ((*it1 == *it2)
+                            && (context.correlation.selection == "AUTO"))
+                        || ((*it1 != *it2)
+                            && context.correlation.selection == "CROSS"))
                     {
-                        const pair<int, int> baseline(*it1, *it2);
-                        
-                        map<pair<int, int>, int>::const_iterator index = itsSelectedBaselines.find(baseline);
-                        
-                        if(index != itsSelectedBaselines.end())
-                        {
-                            itsBLInx.push_back(index->second);
-                        }
+                        baseline_t baseline(*it1, *it2);
+
+                        if (itsChunkData->hasBaseline(baseline))
+                            itsContext.baselines.insert(baseline);
                     }
                 }
             }
@@ -519,169 +427,63 @@ bool Prediffer::setContext(const Context &context)
             ++baseline_it2;
         }
     }
-    ASSERTSTR(itsBLInx.size() > 0, "No baselines selected in current context.");
-    
-    // Clear the solvable flag on all parameters (may still be set from the
-    // previous step.
-    clearSolvableParms();
-    
-    // Create the measurement equation for each interferometer (baseline).
-    if(context.sources.empty())
-        // If no sources are specified, use all available sources.
-        makeTree(context.instrumentModel, itsSources->getSourceNames());
-    else
-        makeTree(context.instrumentModel, context.sources);
 
-    // Put funklets in parms which are not filled yet. (?)
-    for (MeqParmGroup::iterator it = itsParmGroup.begin();
-        it != itsParmGroup.end();
-        ++it)
+    if(itsContext.baselines.empty())
     {
-        it->second.fillFunklets(itsParmValues, itsWorkDomain);
+        LOG_ERROR("At least one baseline should be selected.");
+        return false;
     }
-    
+
     return true;
 }
 
 
-MeqDomain Prediffer::getLocalDataDomain() const
+bool Prediffer::setContext(const PredictContext &context)
 {
-    return MeqDomain(itsStartFreq,
-        itsEndFreq,
-        itsMSDesc.times.front() - itsMSDesc.exposures.front() / 2,
-        itsMSDesc.times.back() + itsMSDesc.exposures.back() / 2);
-}
+    if(!setContext(dynamic_cast<const Context &>(context)))
+    {
+        return false;
+    }
 
+    // Create the measurement equation for each interferometer (baseline).
+    itsModel->makeEquations(Model::PREDICT, context.instrumentModel,
+        itsContext.baselines, context.sources, itsParmGroup,
+        itsInstrumentDBase.get(), &itsPhaseRef, itsChunkData);
 
-bool Prediffer::setWorkDomain(const MeqDomain &domain)
-{
-    // Determine channel with lower border closest to specified start frequency.
-    int startChan = int(0.5 + (domain.startX() - itsStartFreq) / itsStepFreq);
-    
-    // Determine channel with upper border closest to specified end frequency.
-    int endChan   = int(0.5 + (domain.endX() - itsStartFreq) / itsStepFreq) - 1;
-  
-    // Exit if the MS has no overlap in frequency with the specified work domain.
-    if(endChan < 0 || startChan >= itsNrChan)
-        return false;
-        
-    // Clip start/end channel against the MS domain.
-    if(startChan < 0)
-        itsFirstChan = 0;
-    else
-        itsFirstChan = startChan;
-  
-    if(endChan > itsNrChan - 1)
-        itsLastChan = itsNrChan - 1;
-    else
-        itsLastChan = endChan;
-  
-    ASSERT (itsFirstChan <= itsLastChan);
-  
-    // Find the times matching the given time interval.
-    double startTime = domain.startY();
-  
-    // Usually the work domain is shifted sequentially in time,
-    // so we can start the search for the start of the specified
-    // work domain from the end of the previous work domain.
-    
-    // Compute the end of the previous work domain.
-    itsTimeIndex += itsNrTimes;
-  
-    // If necessary, restart the search at the beginning.
-    if(itsTimeIndex >= itsMSDesc.times.size() || startTime < itsMSDesc.times[itsTimeIndex])
-        itsTimeIndex = 0;
-    
-    // Find the index of the time sample with lower border closest
-    // to the specified start time.
-    while(itsTimeIndex < itsMSDesc.times.size() && startTime > itsMSDesc.times[itsTimeIndex])
-        ++itsTimeIndex;
-  
-    // Exit if the MS has no overlap in time with the specified work domain.
-    if(itsTimeIndex >= itsMSDesc.times.size())
-        return false;
-  
-    // Compute the actual start time (i.e. the lower border of
-    // the selected time sample.
-    startTime = itsMSDesc.times[itsTimeIndex] - itsMSDesc.exposures[itsTimeIndex] / 2;
-    
-    // Find the index of the time sample with the upper bound closest
-    // to the specified end time.
-    itsNrTimes = 0;
-    double endTime = domain.endY();
-    unsigned int endIndex = itsTimeIndex;
-    while(endIndex < itsMSDesc.times.size() && endTime >= itsMSDesc.times[endIndex])
+    // Put funklets in parms which are not filled yet. (?)
+    for(MeqParmGroup::iterator it = itsParmGroup.begin();
+        it != itsParmGroup.end();
+        ++it)
     {
-        ++endIndex;
-        ++itsNrTimes;
+        it->second.fillFunklets(itsParmValues, itsWorkDomain);
     }
-    ASSERT(itsNrTimes > 0);
-
-    // Compute the actual end time (i.e. the upper border of
-    // the selected time sample.
-    endTime = itsMSDesc.times[endIndex - 1] + itsMSDesc.exposures[endIndex - 1] / 2;
-  
-    itsWorkDomain = MeqDomain(itsStartFreq + itsFirstChan * itsStepFreq,
-        itsStartFreq + (itsLastChan + 1) * itsStepFreq,
-        startTime,
-        endTime);
-        
-    // Read all parameter values which are part of the work domain.
-    readParms();
-    
-    // Display work domain.
-    LOG_INFO_STR("Work domain: " << setprecision(10) << itsWorkDomain);
-    LOG_INFO_STR("  + Bandwidth: " << setprecision(3) << (itsLastChan + 1 - itsFirstChan) * itsStepFreq / 1000.0
-        << " kHz [Channel " << itsFirstChan << " - " << itsLastChan << ", " << itsStepFreq / 1000.0
-        << " kHz/channel]");
-    LOG_INFO_STR("  + Time: " << (endTime - startTime) / 60.0 << " minutes [Sample " << itsTimeIndex << " - "
-        << endIndex - 1 << ", " << (endTime - startTime) / itsNrTimes << " s/sample on average]");
-    
-    return true;
-}
 
-
-bool Prediffer::setWorkDomain(int startChan, int endChan, double tstart, double tlength)
-{
-  // Determine the first and last channel to process.
-  if (startChan < 0) {
-    startChan = 0;
-  }
-  if (endChan < 0  ||  endChan >= itsNrChan) {
-    endChan = itsNrChan-1;
-  }
-  return setWorkDomain (MeqDomain(itsStartFreq + startChan*itsStepFreq,
-                  itsStartFreq + (endChan+1)*itsStepFreq,
-                  tstart,
-                  tstart+tlength));
+    itsOutputColumn = context.outputColumn;
+    return true;
 }
 
 
-bool Prediffer::setWorkDomain(double startFreq, double endFreq, double startTime, double endTime)
-{
-    return setWorkDomain(MeqDomain(startFreq, endFreq, startTime, endTime));
-}
-
-bool Prediffer::setContext(const PredictContext &context)
+bool Prediffer::setContext(const SubtractContext &context)
 {
     if(!setContext(dynamic_cast<const Context &>(context)))
     {
         return false;
     }
-    
-    itsOutDataColumn = context.outputColumn;
-    return true;
-}
 
+    // Create the measurement equation for each interferometer (baseline).
+    itsModel->makeEquations(Model::PREDICT, context.instrumentModel,
+        itsContext.baselines, context.sources, itsParmGroup,
+        itsInstrumentDBase.get(), &itsPhaseRef, itsChunkData);
 
-bool Prediffer::setContext(const SubtractContext &context)
-{
-    if(!setContext(dynamic_cast<const Context &>(context)))
+    // Put funklets in parms which are not filled yet. (?)
+    for(MeqParmGroup::iterator it = itsParmGroup.begin();
+        it != itsParmGroup.end();
+        ++it)
     {
-        return false;
+        it->second.fillFunklets(itsParmValues, itsWorkDomain);
     }
-    
-    itsOutDataColumn = context.outputColumn;
+
+    itsOutputColumn = context.outputColumn;
     return true;
 }
 
@@ -692,8 +494,22 @@ bool Prediffer::setContext(const CorrectContext &context)
     {
         return false;
     }
-    
-    itsOutDataColumn = context.outputColumn;
+
+    // Create the measurement equation for each interferometer (baseline).
+    itsModel->makeEquations(Model::CORRECT, context.instrumentModel,
+        itsContext.baselines, context.sources, itsParmGroup,
+        itsInstrumentDBase.get(), &itsPhaseRef, itsChunkData);
+
+    // Put funklets in parms which are not filled yet. (?)
+    for(MeqParmGroup::iterator it = itsParmGroup.begin();
+        it != itsParmGroup.end();
+        ++it)
+    {
+        it->second.fillFunklets(itsParmValues, itsWorkDomain);
+    }
+
+
+    itsOutputColumn = context.outputColumn;
     return true;
 }
 
@@ -704,1320 +520,836 @@ bool Prediffer::setContext(const GenerateContext &context)
     {
         return false;
     }
-    
-    const vector<string>& unknowns = context.unknowns;
-    const vector<string>& excludedUnknowns = context.excludedUnknowns;
-    
-    vector<casa::Regex> unknownsRegex;
-    vector<casa::Regex> excludedUnknownsRegex;
+
+    // Create the measurement equation for each interferometer (baseline).
+    itsModel->makeEquations(Model::PREDICT, context.instrumentModel,
+        itsContext.baselines, context.sources, itsParmGroup,
+        itsInstrumentDBase.get(), &itsPhaseRef, itsChunkData);
+
+    // Put funklets in parms which are not filled yet. (?)
+    for(MeqParmGroup::iterator it = itsParmGroup.begin();
+        it != itsParmGroup.end();
+        ++it)
+    {
+        it->second.fillFunklets(itsParmValues, itsWorkDomain);
+    }
+
+    // Clear the solvable flag on all parameters (may still be set from the
+    // previous step.
+    clearSolvableParms();
+
+    // Convert patterns to AIPS++ regular expression objects.
+    vector<casa::Regex> included(context.unknowns.size());
+    vector<casa::Regex> excluded(context.excludedUnknowns.size());
 
     try
     {
-        // Convert patterns to aips++ regexes.
-        for(unsigned int i = 0; i < unknowns.size(); i++)
-        {
-            unknownsRegex.push_back(casa::Regex::fromPattern(unknowns[i]));
-        }
-    
-        for(unsigned int i = 0; i < excludedUnknowns.size(); i++)
-        {
-            excludedUnknownsRegex.push_back(casa::Regex::fromPattern(excludedUnknowns[i]));
-        }
+        transform(context.unknowns.begin(), context.unknowns.end(),
+            included.begin(), ptr_fun(casa::Regex::fromPattern));
+
+        transform(context.excludedUnknowns.begin(),
+            context.excludedUnknowns.end(), excluded.begin(),
+            ptr_fun(casa::Regex::fromPattern));
     }
-    catch(exception &_ex)
+    catch(std::exception &_ex)
     {
-        LOG_ERROR_STR("Error parsing Parms/ExclParms regular expression (exception: " << _ex.what() << ")");
+        LOG_ERROR_STR("Error parsing Parms/ExclParms pattern (exception: "
+            << _ex.what() << ")");
         return false;
     }
-    
+
     // Find all parms matching context.unknowns, exclude those that
     // match context.excludedUnknowns.
-    int unknownCount = 0;
     for(MeqParmGroup::iterator parameter_it = itsParmGroup.begin();
         parameter_it != itsParmGroup.end();
         ++parameter_it)
     {
-        String parameterName(parameter_it->second.getName());
+        casa::String name(parameter_it->second.getName());
 
         // Loop through all regex-es until a match is found.
-        for(vector<casa::Regex>::iterator included_it = unknownsRegex.begin();
-            included_it != unknownsRegex.end();
-            included_it++)
+        for(vector<casa::Regex>::iterator included_it = included.begin();
+            included_it != included.end();
+            ++included_it)
         {
-            if(parameterName.matches(*included_it))
+            if(name.matches(*included_it))
             {
                 bool include = true;
-                
+
                 // Test if excluded.
-                for(vector<casa::Regex>::const_iterator excluded_it = excludedUnknownsRegex.begin();
-                    excluded_it != excludedUnknownsRegex.end();
-                    excluded_it++)
+                for(vector<casa::Regex>::const_iterator excluded_it =
+                    excluded.begin();
+                    excluded_it != excluded.end();
+                    ++excluded_it)
                 {
-                    if(parameterName.matches(*excluded_it))
+                    if(name.matches(*excluded_it))
                     {
                         include = false;
                         break;
                     }
                 }
-        
+
                 if(include)
-                {
-                    LOG_TRACE_OBJ_STR("setSolvable: " << parameter_it->second.getName());
                     parameter_it->second.setSolvable(true);
-                    unknownCount++;
-                }
-                
+
                 break;
             }
         }
     }
-    
-    if(unknownCount == 0)
-    {
-        LOG_ERROR("No unknowns selected in this context.");
-        return false;
-    }
-                        
-    itsSolveDomains = context.solveDomains;
-//    initSolvableParms(itsSolveDomains);
-    initializeSolveDomains(context.solveDomains);
-    
-    return itsNrPert>0;
-}
 
+    // Initialize solve domain grid.
+    pair<size_t, size_t> domainSize(context.domainSize);
+    if(domainSize.first == 0 || domainSize.first > itsChunkData->freq.size())
+        domainSize.first = itsChunkData->freq.size();
+    if(domainSize.second == 0 || domainSize.second > itsChunkData->time.size())
+        domainSize.second = itsChunkData->time.size();
 
-void Prediffer::predictVisibilities()
-{
-    writePredictedData();
-}
+    LOG_DEBUG_STR("Nominal solve domain size: " << domainSize.first
+        << " channels by " << domainSize.second << " timeslots.");
 
+    initializeSolveDomains(domainSize);
 
-void Prediffer::subtractVisibilities()
-{
-    subtractData();
+    return (itsContext.derivativeCount > 0);
 }
 
 
-void Prediffer::correctVisibilities()
+void Prediffer::predict()
 {
-    correctData();
-}
+    process(false, true, false, make_pair(0, 0),
+        make_pair(itsChunkData->freq.size() - 1, itsChunkData->time.size() - 1),
+        &Prediffer::predictBaseline, 0);
 
+    if(!itsOutputColumn.empty())
+        itsMeasurement->write(itsChunkSelection, itsChunkData, itsOutputColumn,
+            false);
 
-void Prediffer::generateEquations(vector<casa::LSQFit> &equations)
-{
-    fillFitters(equations);
+    LOG_DEBUG_STR("Predict: " << itsPredTimer);
+    LOG_DEBUG_STR("Copy: " << itsEqTimer);
+    itsPredTimer.reset();
+    itsEqTimer.reset();
 }
 
 
-//-----------------------[ Model ]-----------------------//
-
-
-void Prediffer::makeTree (const vector<string>& modelType,
-              const vector<string>& sourceNames)
+void Prediffer::subtract()
 {
-  // Determine which parts of the model to use.
-  bool asAP = true;
-  bool useDipole = false;
-  bool usePatchGain = false;
-  bool useTotalGain = false;
-  bool useBandpass = false;
-  for (uint i=0; i<modelType.size(); ++i) {
-    if (modelType[i] != "") {
-      if (modelType[i] == "TOTALGAIN") {
-    useTotalGain = true;
-      } else if (modelType[i] == "PATCHGAIN") {
-    usePatchGain = true;
-      } else if (modelType[i] == "REALIMAG") {
-    asAP = false;
-      } else if (modelType[i] == "DIPOLE") {
-    useDipole = true;
-      } else if (modelType[i] == "BANDPASS") {
-    useBandpass = true;
-      } else {
-    ASSERTSTR (false, "Modeltype part " << modelType[i] << " is invalid; "
-           "valid are TOTALGAIN,PATCHGAIN,REALIMAG,DIPOLE,BANDPASS");
-      }
-    }
-  }
-  
-  LOG_INFO_STR("Instrument model:"
-    << (asAP ? "" : " REALIMAG") 
-    << (useDipole ? " DIPOLE" : "") 
-    << (useTotalGain ? " TOTALGAIN" : "") 
-    << (usePatchGain ? " PATCHGAIN" : "") 
-    << (useBandpass ? " BANDPASS" : ""));
-  
-  // Find all sources and groups to use.
-  // Make an LMN node for each source used.
-  int nrsrc = sourceNames.size();
-  vector<MeqSource*> sources;
-  map<string,vector<int> > groups;
-  itsLMN.clear();
-  itsLMN.reserve (nrsrc);
-  for (int i=0; i<nrsrc; ++i) {
-    MeqSource* src = itsSources->getSource (sourceNames[i]);
-    // Add source to list.
-    sources.push_back (src);
-    // Add source index to group.
-    groups[src->getGroupName()].push_back (i);
-    MeqLMN* lmn = new MeqLMN(src);
-    lmn->setPhaseRef (&itsPhaseRef);
-    itsLMN.push_back (lmn);
-  }
-  // Set up the expression tree for all baselines.
-  makeLOFARExprs (sources, groups,
-          useTotalGain, usePatchGain, asAP, useDipole, useBandpass);
-}
+    process(false, true, false, make_pair(0, 0),
+        make_pair(itsChunkData->freq.size() - 1, itsChunkData->time.size() - 1),
+        &Prediffer::subtractBaseline, 0);
 
-void Prediffer::makeLOFARExprs (const vector<MeqSource*>& sources,
-                const map<string, vector<int> >& groups,
-                bool useTotalGain, bool usePatchGain,
-                bool asAP,
-                bool useDipole, bool useBandpass)
-{
-  // Allocate the vectors holding the expressions.
-  int nrstat = itsStations.size();
-  int nrsrc  = sources.size();
-  int nrgrp  = groups.size();
-  // GJ is real/imag or ampl/phase
-  string gjname1 = "real:";
-  string gjname2 = "imag:";
-  if (asAP) {
-    gjname1 = "ampl:";
-    gjname2 = "phase:";
-  }
-  // Vector containing DipoleExpr-s.
-  vector<MeqJonesExpr> dipoleExpr(nrstat);
-  // Vector containing DFTPS-s.
-  vector<MeqExpr> pdfts(nrsrc*nrstat);
-  // Vector containing all gains per station per patch.
-  vector<MeqJonesExpr> patchGJ(nrgrp*nrstat);
-  // Vector containing all Gain-s per station.
-  vector<MeqJonesExpr> totalGJ(nrstat);
-  // Correction per station.
-  vector<MeqJonesExpr> corrStat(nrstat);
-  // Bandpass per station.
-  vector<MeqJonesExpr> bandpass(nrstat);
-
-  // Fill the vectors for each station.
-  for (int stat=0; stat<nrstat; ++stat) {
-    // Do it only if the station is actually used.
-    if (itsSelStations[stat] != 0) {
-      // Do pure station parameters only if told so.
-      if (useDipole) {
-    MeqExpr frot (MeqParmFunklet::create ("frot:" +
-                          itsStations[stat]->getName(),
-                          itsParmGroup, itsMEP));
-    MeqExpr drot (MeqParmFunklet::create ("drot:" +
-                          itsStations[stat]->getName(),
-                          itsParmGroup, itsMEP));
-    MeqExpr dell (MeqParmFunklet::create ("dell:" +
-                          itsStations[stat]->getName(),
-                          itsParmGroup, itsMEP));
-    MeqExpr gj11 (MeqParmFunklet::create ("dgain:X:" +
-                          itsStations[stat]->getName(),
-                          itsParmGroup, itsMEP));
-    MeqExpr gj22 (MeqParmFunklet::create ("dgain:Y:" +
-                          itsStations[stat]->getName(),
-                          itsParmGroup, itsMEP));
-    dipoleExpr[stat] = MeqJonesExpr(new MeqStatExpr (frot, drot, dell,
-                             gj11, gj22));
-      }
-      // Make a bandpass per station
-      if (useBandpass) {
-        string stationName = itsStations[stat]->getName();
-        MeqExpr bandpassXX(MeqParmFunklet::create("bandpass:X:" + stationName,
-                          itsParmGroup, itsMEP));
-        MeqExpr bandpassYY(MeqParmFunklet::create("bandpass:Y:" + stationName,
-                          itsParmGroup, itsMEP));
-
-        bandpass[stat] = new MeqDiag(MeqExpr(bandpassXX), MeqExpr(bandpassYY));
-      }
-      // Make a DFT per station per source.
-      for (int src=0; src<nrsrc; ++src) {
-    pdfts[stat*nrsrc + src] = MeqExpr(new MeqDFTPS (itsLMN[src],
-                            itsStatUVW[stat]));
-      }
-      // Make optionally GJones expressions.
-      MeqExprRep* gj11;
-      MeqExprRep* gj12;
-      MeqExprRep* gj21;
-      MeqExprRep* gj22;
-      if (useTotalGain) {
-    // Make a gain/phase expression per station.
-    string nm = itsStations[stat]->getName();
-    MeqExpr gj11r (MeqParmFunklet::create ("gain:11:" + gjname1 + nm,
-                           itsParmGroup, itsMEP));
-    MeqExpr gj11i (MeqParmFunklet::create ("gain:11:" + gjname2 + nm,
-                           itsParmGroup, itsMEP));
-    MeqExpr gj12r (MeqParmFunklet::create ("gain:12:" + gjname1 + nm,
-                           itsParmGroup, itsMEP));
-    MeqExpr gj12i (MeqParmFunklet::create ("gain:12:" + gjname2 + nm,
-                           itsParmGroup, itsMEP));
-    MeqExpr gj21r (MeqParmFunklet::create ("gain:21:" + gjname1 + nm,
-                           itsParmGroup, itsMEP));
-    MeqExpr gj21i (MeqParmFunklet::create ("gain:21:" + gjname2 + nm,
-                           itsParmGroup, itsMEP));
-    MeqExpr gj22r (MeqParmFunklet::create ("gain:22:" + gjname1 + nm,
-                           itsParmGroup, itsMEP));
-    MeqExpr gj22i (MeqParmFunklet::create ("gain:22:" + gjname2 + nm,
-                           itsParmGroup, itsMEP));
-    if (asAP) {
-      gj11 = new MeqExprAPToComplex (gj11r, gj11i);
-      gj12 = new MeqExprAPToComplex (gj12r, gj12i);
-      gj21 = new MeqExprAPToComplex (gj21r, gj21i);
-      gj22 = new MeqExprAPToComplex (gj22r, gj22i);
-    } else {
-      gj11 = new MeqExprToComplex (gj11r, gj11i);
-      gj12 = new MeqExprToComplex (gj12r, gj12i);
-      gj21 = new MeqExprToComplex (gj21r, gj21i);
-      gj22 = new MeqExprToComplex (gj22r, gj22i);
-    }
-    totalGJ[stat] = new MeqJonesNode (MeqExpr(gj11), MeqExpr(gj12),
-                      MeqExpr(gj21), MeqExpr(gj22));
-    corrStat[stat] = new MeqJonesInvert (totalGJ[stat]);
-      }
-      if (usePatchGain) {
-    // Make a complex gain expression per station per patch.
-    int grp=0;
-    for (map<string,vector<int> >::const_iterator grpiter = groups.begin();
-         grpiter != groups.end();
-         grpiter++, grp++) {
-      string nm = itsStations[stat]->getName() + ":" + grpiter->first;
-      MeqExpr gj11r (MeqParmFunklet::create ("gain:11:" + gjname1 + nm,
-                         itsParmGroup, itsMEP));
-      MeqExpr gj11i (MeqParmFunklet::create ("gain:11:" + gjname2 + nm,
-                         itsParmGroup, itsMEP));
-      MeqExpr gj12r (MeqParmFunklet::create ("gain:12:" + gjname1 + nm,
-                         itsParmGroup, itsMEP));
-      MeqExpr gj12i (MeqParmFunklet::create ("gain:12:" + gjname2 + nm,
-                         itsParmGroup, itsMEP));
-      MeqExpr gj21r (MeqParmFunklet::create ("gain:21:" + gjname1 + nm,
-                         itsParmGroup, itsMEP));
-      MeqExpr gj21i (MeqParmFunklet::create ("gain:21:" + gjname2 + nm,
-                         itsParmGroup, itsMEP));
-      MeqExpr gj22r (MeqParmFunklet::create ("gain:22:" + gjname1 + nm,
-                         itsParmGroup, itsMEP));
-      MeqExpr gj22i (MeqParmFunklet::create ("gain:22:" + gjname2 + nm,
-                         itsParmGroup, itsMEP));
-      if (asAP) {
-        gj11 = new MeqExprAPToComplex (gj11r, gj11i);
-        gj12 = new MeqExprAPToComplex (gj12r, gj12i);
-        gj21 = new MeqExprAPToComplex (gj21r, gj21i);
-        gj22 = new MeqExprAPToComplex (gj22r, gj22i);
-      } else {
-        gj11 = new MeqExprToComplex (gj11r, gj11i);
-        gj12 = new MeqExprToComplex (gj12r, gj12i);
-        gj21 = new MeqExprToComplex (gj21r, gj21i);
-        gj22 = new MeqExprToComplex (gj22r, gj22i);
-      }
-      patchGJ[stat*nrgrp + grp] = new MeqJonesNode (MeqExpr(gj11),
-                            MeqExpr(gj12),
-                            MeqExpr(gj21),
-                            MeqExpr(gj22));
-      // Only AP of first group is used for correction.
-      if (grp == 0) {
-        corrStat[stat] = new MeqJonesInvert (patchGJ[stat*nrgrp + grp]);
-      }
-    }
-      }
-    }
-  }
-  // Make an expression for each baseline.
-  int nrusedbl = itsBLInx.size();
-  itsExpr.resize (nrusedbl);
-  itsCorrExpr.resize (nrusedbl);
-  itsCorrMMap.resize (nrusedbl);
-  for (int blindex=0; blindex<nrusedbl; blindex++) {
-    int bl = itsBLInx[blindex];
-    int ant1 = itsMSDesc.ant1[bl];
-    int ant2 = itsMSDesc.ant2[bl];
-    if (usePatchGain || useTotalGain) {
-      // Make correction expressions.
-      itsCorrMMap[blindex] = new MeqJonesMMap (itsMSMapInfo, bl);
-      itsCorrExpr[blindex] = new MeqJonesCMul3 (corrStat[ant1],
-                        itsCorrMMap[blindex],
-                        corrStat[ant2]);
-    }
-    // Predict expressions.
-    vector<MeqJonesExpr> vecPatch;
-    // Loop through all source groups.
-    int grp=0;
-    for (map<string,vector<int> >::const_iterator grpiter = groups.begin();
-     grpiter != groups.end();
-     grpiter++, grp++) {
-      const vector<int>& srcgrp = grpiter->second;;
-      vector<MeqJonesExpr> vecSrc;
-      vecSrc.reserve (srcgrp.size());
-      for (uint j=0; j<srcgrp.size(); ++j) {
-    // Create the total DFT per source.
-    int src = srcgrp[j];
-    MeqExpr expr1 (new MeqBaseDFTPS (pdfts[ant1*nrsrc + src],
-                     pdfts[ant2*nrsrc + src],
-                     itsLMN[src]));
-    // For the time being only point sources are supported.
-    MeqPointSource& mps = dynamic_cast<MeqPointSource&>(*sources[src]);
-    vecSrc.push_back (MeqJonesExpr (new MeqBaseLinPS(expr1, &mps)));
-      }
-      MeqJonesExpr sum;
-      // Sum all sources in the group.
-      if (vecSrc.size() == 1) {
-    sum = vecSrc[0];
-      } else {
-    sum = MeqJonesExpr (new MeqJonesSum(vecSrc));
-      }
-      // Multiply by ionospheric gain/phase per station per patch.
-      if (usePatchGain) {
-    vecPatch.push_back (new MeqJonesCMul3(patchGJ[ant1*nrgrp + grp],
-                          sum,
-                          patchGJ[ant2*nrgrp + grp]));
-      } else {
-    vecPatch.push_back (sum);
-      }
-    }
-    // Sum all patches.
-    MeqJonesExpr sumAll;
-    if (vecPatch.size() == 1) {
-      sumAll = vecPatch[0];
-    } else {
-      sumAll = MeqJonesExpr (new MeqJonesSum(vecPatch));
-    }
-    // Multiply by total gain/phase per station.
-    if (useTotalGain) {
-      sumAll = new MeqJonesCMul3(totalGJ[ant1],
-                 sumAll,
-                 totalGJ[ant2]);
-    }
-    if (useBandpass) {
-      sumAll = new MeqJonesCMul3(bandpass[ant1],
-                 sumAll,
-                 bandpass[ant2]);
-    }
-    if (useDipole) {
-      sumAll = new MeqJonesCMul3(dipoleExpr[ant1],
-                 sumAll,
-                 dipoleExpr[ant2]);
-    }
-    itsExpr[blindex] = sumAll;
-  }
-}
+    if(!itsOutputColumn.empty())
+        itsMeasurement->write(itsChunkSelection, itsChunkData, itsOutputColumn,
+            false);
 
-void Prediffer::setPrecalcNodes (vector<MeqJonesExpr>& nodes)
-{
-  // First clear the levels of all nodes in the tree.
-  for (uint i=0; i<nodes.size(); ++i) {
-    if (! nodes[i].isNull()) {
-      nodes[i].clearDone();
-    }
-  }
-  // Now set the levels of all nodes in the tree.
-  // The top nodes have level 0; lower nodes have 1, 2, etc..
-  int nrLev = -1;
-  for (uint i=0; i<nodes.size(); ++i) {
-    if (! nodes[i].isNull()) {
-      nrLev = max (nrLev, nodes[i].setLevel(0));
-    }
-  }
-  nrLev++;
-  ASSERT (nrLev > 0);
-  itsPrecalcNodes.resize (nrLev);
-  // Find the nodes to be precalculated at each level.
-  // That is not needed for the root nodes (the baselines).
-  // The nodes used by the baselines are always precalculated (even if
-  // having one parent).
-  // It may happen that a station is used by only one baseline. Calculating
-  // such a baseline is much more work if the station was not precalculated.
-  for (int level=1; level<nrLev; ++level) {
-    vector<MeqExprRep*>& pcnodes = itsPrecalcNodes[level];
-    pcnodes.resize (0);
-    for (vector<MeqJonesExpr>::iterator iter=nodes.begin();
-     iter != nodes.end();
-     ++iter) {
-      if (! iter->isNull()) {
-    iter->getCachingNodes (pcnodes, level, false);
-      }
-    }
-  }
-  LOG_TRACE_FLOW_STR("#levels=" << nrLev);
-  for (int i=0; i<nrLev; ++i) {
-    LOG_TRACE_FLOW_STR("#expr on level " << i << " is " << itsPrecalcNodes[i].size());
-  }
+    LOG_DEBUG_STR("Predict: " << itsPredTimer);
+    LOG_DEBUG_STR("Subtract: " << itsEqTimer);
+    itsPredTimer.reset();
+    itsEqTimer.reset();
 }
 
-void Prediffer::precalcNodes (const MeqRequest& request)
-{
-#pragma omp parallel
-  {
-    // Loop through expressions to be precalculated.
-    // At each level the expressions can be executed in parallel.
-    // Level 0 is formed by itsExpr which are not calculated here.
-    for (int level = itsPrecalcNodes.size(); --level > 0;) {
-      vector<MeqExprRep*>& exprs = itsPrecalcNodes[level];
-      int nrExprs = exprs.size();
-      if (nrExprs > 0) {
-#pragma omp for schedule(dynamic)
-    for (int i=0; i<nrExprs; ++i) {
-      exprs[i]->precalculate (request);
-    }
-      }
-    }
-  } // end omp parallel
-}
-
-//-----------------------[ MS Access ]-----------------------//
 
-void Prediffer::readMeasurementSetMetaData(const string &fileName)
+void Prediffer::correct()
 {
-    MeasurementSet ms(fileName);
-
-    Path absolutePath = Path(fileName).absoluteName();
-    itsMSDesc.msPath = absolutePath.dirName();
-    itsMSDesc.msName = absolutePath.baseName();
-    itsMSDesc.npart  = 1;
-
-    /*
-      Get baselines.
-    */
-    Block<String> sortColumns(2);
-    sortColumns[0] = "ANTENNA1";
-    sortColumns[1] = "ANTENNA2";
-    Table uniqueBaselines = ms.sort(sortColumns, Sort::Ascending, Sort::QuickSort + Sort::NoDuplicates);
-    ROScalarColumn<Int> station1Column(uniqueBaselines, "ANTENNA1");
-    ROScalarColumn<Int> station2Column(uniqueBaselines, "ANTENNA2");
-    station1Column.getColumn().tovector(itsMSDesc.ant1);
-    station2Column.getColumn().tovector(itsMSDesc.ant2);
-
-    /*
-      Get information about frequency grid.
-    */
-    MSDataDescription dataDescription(ms.dataDescription());
-    ROMSDataDescColumns dataDescriptionColumns(dataDescription);
-    MSSpectralWindow spectralWindow(ms.spectralWindow());
-    ROMSSpWindowColumns spectralWindowColumns(spectralWindow);
-    int spectralWindowCount = dataDescription.nrow();
-
-    itsMSDesc.nchan.resize(spectralWindowCount);
-    itsMSDesc.startFreq.resize(spectralWindowCount);
-    itsMSDesc.endFreq.resize(spectralWindowCount);
-
-    for(int i = 0; i < spectralWindowCount; i++)
-    {
-        // _Center_ frequencies for each channel
-        Vector<double> channelFrequency = spectralWindowColumns.chanFreq()(i);
-        // Channel width for each channel
-        Vector<double> channelWidth = spectralWindowColumns.chanWidth()(i);
+    process(false, true, false, make_pair(0, 0),
+        make_pair(itsChunkData->freq.size() - 1, itsChunkData->time.size() - 1),
+        &Prediffer::correctBaseline, 0);
 
-        // So far, only equal frequency spacings are possible.
-        ASSERTSTR(allEQ(channelWidth, channelWidth(0)), "Channels must have equal spacings");
+    if(!itsOutputColumn.empty())
+        itsMeasurement->write(itsChunkSelection, itsChunkData, itsOutputColumn,
+            false);
 
-        int channelCount = channelWidth.nelements();
-        itsMSDesc.nchan[i] = channelCount;
+    LOG_DEBUG_STR("Correct: " << itsEqTimer);
+    LOG_DEBUG_STR("Copy: " << itsPredTimer);
+    itsPredTimer.reset();
+    itsEqTimer.reset();
+}
 
-        double step = abs(channelWidth(0));
-        if(channelFrequency(0) > channelFrequency(channelCount - 1))
-        {
-            // Channels are in reverse order! NB: startFreq and endFreq are left
-            // in reverse order because they are swapped in processMSDesc().
-            
-            // Upper border of last channel.
-            itsMSDesc.startFreq[i] = channelFrequency(0) + step / 2;
-            // Lower border of first channel.
-            itsMSDesc.endFreq[i]   = itsMSDesc.startFreq[i] - channelCount * step;
-        }
-        else
-        {
-            // Lower border of first channel.
-            itsMSDesc.startFreq[i] = channelFrequency(0) - step / 2;
-            // Upper border of last channel.
-            itsMSDesc.endFreq[i]   = itsMSDesc.startFreq[i] + channelCount * step;
-        }
-    }
 
-    /*
-      Get information about time grid.
-    */
-    ROScalarColumn<double> timeColumn(ms, "TIME");
-    Vector<double> time = timeColumn.getColumn();
-    Vector<uInt> timeIndex;
-    uInt timeCount = GenSortIndirect<double>::sort(timeIndex, time, Sort::Ascending, Sort::InsSort + Sort::NoDuplicates);
+void Prediffer::generate(pair<size_t, size_t> start, pair<size_t, size_t> end,
+    vector<casa::LSQFit> &solvers)
+{
+    ASSERT(start.first <= end.first
+        && end.first < itsContext.domainCount.first);
+    ASSERT(start.second <= end.second
+        && end.second < itsContext.domainCount.second);
 
-    itsMSDesc.times.resize(timeCount);
-    itsMSDesc.exposures.resize(timeCount);
-    ROScalarColumn<double> exposureColumn(ms, "EXPOSURE");
-    Vector<double> exposure = exposureColumn.getColumn();
+    size_t nFreqDomains = end.first - start.first + 1;
+    size_t nTimeDomains = end.second - start.second + 1;
+    size_t nDomains = nFreqDomains * nTimeDomains;
+    ASSERT(solvers.size() >= nDomains);
 
-    for(uInt i = 0; i < timeCount; i++)
-    {
-        // _Center_ of integration interval.
-        itsMSDesc.times[i] = time[timeIndex[i]];
-        // Effective integration time.
-        itsMSDesc.exposures[i] = exposure[timeIndex[i]];
-    }
+#ifdef COMPUTE_SQUARED_ERROR
+    itsSquaredErrorReal.resize(nDomains);
+    itsSquaredErrorImag.resize(nDomains);
+    fill(itsSquaredErrorReal.begin(), itsSquaredErrorReal.end(), 0.0);
+    fill(itsSquaredErrorImag.begin(), itsSquaredErrorImag.end(), 0.0);
+#endif
 
-    /*
-      Get phase center as RA and DEC (J2000).
-     
-      From AIPS++ note 229 (MeasurementSet definition version 2.0):
-      ---
-      FIELD: Field positions for each source
-      Notes:
-      The FIELD table defines a field position on the sky. For interferometers,
-      this is the correlated field position. For single dishes, this is the
-      nominal pointing direction.
-      ---
-
-      In LOFAR/CEP/BB/MS/src/makemsdesc.cc the following line can be found:
-      MDirection phaseRef = mssubc.phaseDirMeasCol()(0)(IPosition(1,0));
-      which should be equivalent to:
-      MDirection phaseRef = mssubc.phaseDirMeas(0);
-      as used in the code below.
-    */
-    MSField field(ms.field());
-    ROMSFieldColumns fieldColumns(field);
-    MDirection phaseCenter = MDirection::Convert(fieldColumns.phaseDirMeas(0), MDirection::J2000)();
-    Quantum<Vector<double> > phaseCenterAngles = phaseCenter.getAngle();
-    itsMSDesc.ra  = phaseCenterAngles.getBaseValue()(0);
-    itsMSDesc.dec = phaseCenterAngles.getBaseValue()(1);
-
-    /*
-      Get correlation types.
-    */
-    MSPolarization polarization(ms.polarization());
-    ROMSPolarizationColumns polarizationColumn(polarization);
-    Vector<Int> correlationTypes = polarizationColumn.corrType()(0);
-    int correlationTypeCount = correlationTypes.nelements();
-    itsMSDesc.corrTypes.resize(correlationTypeCount);
-    for(int i = 0; i < correlationTypeCount; i++)
-    {
-        itsMSDesc.corrTypes[i] = Stokes::name(Stokes::type(correlationTypes(i)));
-    }
+    // Create thread private fitters for parallel execution.
+    vector<vector<casa::LSQFit*> > threadPrivateSolvers(itsNthread);
+    for(size_t i = 0; i < itsNthread; ++i)
+        threadPrivateSolvers[i].resize(nDomains);
 
-    /*
-      Get station names and positions in ITRF coordinates.
-    */
-    MSAntenna antenna(ms.antenna());
-    ROMSAntennaColumns antennaColumns(antenna);
-    int antennaCount = antenna.nrow();
-
-    MVPosition sumVector;
-    itsMSDesc.antNames.resize(antennaCount);
-    itsMSDesc.antPos.resize(IPosition(2, 3, antennaCount));
-    for(int i = 0; i < antennaCount; i++)
+    // Initialize the solver objects.
+    size_t solverIdx = 0;
+    size_t domainIdx =
+        start.second * itsContext.domainCount.first + start.first;
+    for(size_t i = 0; i < nTimeDomains; ++i)
     {
-        itsMSDesc.antNames[i] = antennaColumns.name()(i);
-        MPosition position = antennaColumns.positionMeas()(i);
-        position = MPosition::Convert(position, MPosition::ITRF)();
-        const MVPosition& positionVector = position.getValue();
-        sumVector += positionVector;
-      
-        for(int j = 0; j < 3; j++)
+        for(size_t j = 0; j < nFreqDomains; ++j)
         {
-            itsMSDesc.antPos(IPosition(2, j, i)) = positionVector(j);
-        }
-    }
+//            LOG_DEBUG_STR("Domain (" << j << ", " << i << ") -> "
+//                << domainIdx + j << endl);
 
-    /*
-      Get the array position in ITRF coordinates, or use the centroid
-      of the station positions if the array position is unknown.
-    */
-    MSObservation observation(ms.observation());
-    ROMSObservationColumns observationColumns(observation);
+            size_t nUnknowns =
+                itsContext.domains[domainIdx + j].unknowns.size();
+            solvers[solverIdx].set(nUnknowns);
+            threadPrivateSolvers[0][solverIdx] = &solvers[solverIdx];
 
-    MPosition position;
-    MVPosition positionVector;
-    if(observation.nrow() > 0 && MeasTable::Observatory(position, observationColumns.telescopeName()(0)))
-    {
-        position = MPosition::Convert(position, MPosition::ITRF)();
-        positionVector = position.getValue();
-        //LOG_TRACE_FLOW("Array position: " << position);
-    }
-    else
-    {
-        LOG_WARN("Array position unknown; will use centroid of stations.");
-        positionVector = sumVector * (1.0 / (double) antennaCount);
-    }
+            for(size_t j = 1; j < itsNthread; ++j)
+            {
+                threadPrivateSolvers[j][solverIdx] =
+                    new casa::LSQFit(nUnknowns);
+            }
 
-    itsMSDesc.arrayPos.resize(3);
-    for(int i = 0; i < 3; i++)
-    {
-        itsMSDesc.arrayPos[i] = positionVector(i);
+            ++solverIdx;
+        }
+        domainIdx += itsContext.domainCount.first;
     }
 
-    /*
-      Determine the startTime and endTime of the observation.
-    */
-    if(observation.nrow() > 0)
+    // Size the thread private buffers.
+    for(size_t i = 0; i < itsNthread; ++i)
     {
-        Vector<double> times = observationColumns.timeRange()(0);
-        itsMSDesc.startTime  = times(0);
-        itsMSDesc.endTime    = times(1);
-    }
-    else
+        itsResultVecs[i].resize(2 * itsContext.derivativeCount);
+        itsDiffVecs[i].resize(3 * itsContext.derivativeCount);
+        itsIndexVecs[i].resize(itsContext.derivativeCount);
+    }
+
+    // Convert from solve domain 'coordinates' to sample numbers (i.e. channel
+    // number, timeslot number).
+    pair<size_t, size_t> vstart(start.first * itsContext.domainSize.first,
+        start.second * itsContext.domainSize.second);
+    pair<size_t, size_t> vend
+        ((end.first + 1) * itsContext.domainSize.first - 1,
+        (end.second + 1) * itsContext.domainSize.second - 1);
+    ASSERT(vstart.first < itsChunkData->freq.size());
+    ASSERT(vstart.second < itsChunkData->time.size());
+
+    // Clip against data boundary.
+    if(vend.first >= itsChunkData->freq.size())
+        vend.first = itsChunkData->freq.size() - 1;
+    if(vend.second >= itsChunkData->time.size())
+        vend.second = itsChunkData->time.size() - 1;
+
+//    LOG_DEBUG_STR("Processing visbility domain: " << vstart.first << ", "
+//        << vstart.second << " - " << vend.first << ", " << vend.second <<
+//endl);
+
+    process(true, true, true, vstart, vend, &Prediffer::generateBaseline,
+        &threadPrivateSolvers);
+
+    // Merge the thread-specific solvers into the main ones.
+    for(size_t j = 1; j < itsNthread; ++j)
     {
-        itsMSDesc.startTime = 0.0;
-        itsMSDesc.endTime   = 0.0;
+        for(size_t i = 0; i < nDomains; ++i)
+        {
+            solvers[i].merge(*threadPrivateSolvers[j][i]);
+            delete threadPrivateSolvers[j][i];
+        }
     }
 
-    if(itsMSDesc.startTime >= itsMSDesc.endTime)
+#ifdef COMPUTE_SQUARED_ERROR
+    for(size_t i = 0; i < nDomains; ++i)
     {
-        /*
-          Invalid start / end times; derive from times and interval.
-          Difference between interval and exposure is startup time which
-          is taken into account.
-        */
-        ASSERT(timeCount >= 2);
-        ROScalarColumn<double> interval(ms, "INTERVAL");
-        itsMSDesc.startTime = itsMSDesc.times[0] - itsMSDesc.exposures[0] / 2 + (interval(0) - itsMSDesc.exposures[0]);
-        itsMSDesc.endTime   = itsMSDesc.times[timeCount - 1] + interval(timeCount - 1) / 2;
+        LOG_DEBUG_STR("SquaredError: domain: " << domains.first + i
+            << " real: " << itsSquaredErrorReal[i]
+            << " imaginary: " << itsSquaredErrorImag[i]);
     }
+#endif
 
-    /*
-        Create a map from column name to file on disk.
-    */
-    Record info = ms.dataManagerInfo();
-    for(unsigned int i = 0; i < info.nfields(); ++i)
-    {
-        const Record &dm = info.subRecord(i);
-        const Array<String> columns = dm.asArrayString("COLUMNS");
-        
-        /*
-            BBS requires TiledColumnStMan/TiledShapeStMan (or another StorageManager that
-            stores data linearly on disk) and one column per DataManager. This is because
-            mmap is used to access the data.
-        */
-        if((dm.asString("TYPE") == "TiledColumnStMan" ||
-           dm.asString("TYPE") == "TiledShapeStMan") &&
-           columns.size() == 1)
-        {
-            /*
-                The data bound to a TiledStMan is stored in a file called table.f<seqnr>_TSM<stman> where
-                <seqnr> is SPEC.SEQNR stored in the DataManager info record and <stman> indicates the
-                specific tiled storage manager. If several TiledStMan are used in one MS, they are numbered
-                sequentially. Because there is no easy way to determine which number belongs to which
-                TiledStMan, the mapping created here will not always be correct. However, it is guaranteed
-                to be correct for MSs created by Storage.
-            */
-            unsigned int idx = i;
-            
-            try
-            {
-                const Record &spec = dm.asRecord("SPEC");
-                idx = spec.asuInt("SEQNR");
-            }
-            catch(AipsError &_ex)
-            {
-                LOG_WARN_STR("DataManager " << i + 1 << " has no SPEC.SEQNR. Please verify (e.g. with glish) that the columns bound to this DataManager are stored in " << fileName << "/table.f" << i << "_TSM" << (dm.asString("TYPE") == "TiledColumnStMan" ? "0" : "1") << ".");
-            }
-        
-            /*
-                Update the column map.
-            */
-            ostringstream os;
-            if(dm.asString("TYPE") == "TiledColumnStMan")
-                os << itsMSName << "/table.f" << idx << "_TSM0";
-            else
-                os << itsMSName << "/table.f" << idx << "_TSM1";
-            
-            for(Array<String>::const_iterator it = columns.begin(); it != columns.end(); ++it)
-            {
-                itsColumns[static_cast<string>(*it)] = os.str();
-            }
-        }            
-    }
+    LOG_DEBUG_STR("Predict: " << itsPredTimer);
+    LOG_DEBUG_STR("Construct equations: " << itsEqTimer);
+    itsPredTimer.reset();
+    itsEqTimer.reset();
 }
 
-string Prediffer::getFileForColumn(const string &column)
-{
-    map<string, string>::const_iterator it = itsColumns.find(column);
-    
-    if(it == itsColumns.end())
-        return string();
-    else
-        return it->second;
-}
 
-void Prediffer::processMSDesc (uint ddid)
-{
-  ASSERT (ddid < itsMSDesc.nchan.size());
-  // Set the observation info.
-  itsNCorr     = itsMSDesc.corrTypes.size();
-  itsSelectedCorr.resize(itsNCorr);
-  itsCorr.resize(itsNCorr);
-  itsNrChan    = itsMSDesc.nchan[ddid];
-  itsStartFreq = itsMSDesc.startFreq[ddid];
-  itsEndFreq   = itsMSDesc.endFreq[ddid];
-  itsStepFreq  = (itsEndFreq - itsStartFreq)/itsNrChan;
-  itsNrBl      = itsMSDesc.ant1.size();
-  itsReverseChan = itsStartFreq > itsEndFreq;
-  if (itsReverseChan) {
-    double  tmp  = itsEndFreq;
-    itsEndFreq   = itsStartFreq;
-    itsStartFreq = tmp;
-    itsStepFreq  = abs(itsStepFreq);
-  }
-  // Set the MS info.
-  itsMSMapInfo = MMapMSInfo (itsMSDesc, ddid, itsReverseChan);
-  // Set the phase center info.
-  getPhaseRef (itsMSDesc.ra, itsMSDesc.dec, itsMSDesc.startTime);
-  // Set station info.
-  fillStations();
-}
+//-----------------------[ Parameter Access ]-----------------------//
 
-void Prediffer::getPhaseRef(double ra, double dec, double startTime)
+void Prediffer::readParms()
 {
-  // Use the phase reference of the given J2000 ra/dec.
-  MVDirection mvdir(ra, dec);
-  MDirection phaseRef(mvdir, MDirection::J2000);
-  itsPhaseRef = MeqPhaseRef (phaseRef, startTime);
-}
+    vector<string> emptyvec;
 
+    // Clear all parameter values.
+    itsParmValues.clear();
 
-void Prediffer::fillStations()
-{
-  // Use the array as a 2D one.
-  Matrix<double> antPos (itsMSDesc.antPos);
-  uint nrant = antPos.ncolumn();
-  itsStations = vector<MeqStation*>(nrant, (MeqStation*)0);
-  // Get all stations actually used.
-  for (uint ant=0; ant<nrant; ant++) {
-    // Store each position as a constant parameter.
-    // Use the antenna name as the parameter name.
-    Vector<double> antpos = antPos.column(ant);
-    const string& name = itsMSDesc.antNames[ant];
-    MeqParmSingle* px = new MeqParmSingle("AntPosX." + name,
-                      antpos(0));
-    MeqParmSingle* py = new MeqParmSingle("AntPosY." + name,
-                      antpos(1));
-    MeqParmSingle* pz = new MeqParmSingle("AntPosZ." + name,
-                      antpos(2));
-    itsStations[ant] = new MeqStation(px, py, pz, name);
-  }
-}
+    // Get all parameters that intersect the work domain.
+    LOFAR::ParmDB::ParmDomain pdomain(itsWorkDomain.startX(),
+        itsWorkDomain.endX(), itsWorkDomain.startY(), itsWorkDomain.endY());
+    itsInstrumentDBase->getValues(itsParmValues, emptyvec, pdomain);
+    itsSkyDBase->getValues(itsParmValues, emptyvec, pdomain);
 
-void Prediffer::mapDataFiles (const string& inColumnName,
-                  const string& outColumnName)
-{
-  Table tab;
-  
-  if (! inColumnName.empty()) {
-    string inFile = getFileForColumn(inColumnName);
-    ASSERTSTR(!inFile.empty(), "Column " << inColumnName << " does not exist or has non-standard storage manager.");
-    
-    if (itsInDataMap == 0  ||  itsInDataMap->getFileName() != inFile) {
-      tab = Table(itsMSName);
-      ASSERTSTR (tab.tableDesc().isColumn(inColumnName),
-         "Column " << inColumnName << " does not exist");
-      delete itsInDataMap;
-      itsInDataMap = 0;
-      // See if the input file is the previous output file.
-      if (itsOutDataMap  &&  itsOutDataMap->getFileName() == inFile) {
-    itsInDataMap = itsOutDataMap;
-    itsOutDataMap = 0;
-      } else {
-    itsInDataMap = new MMap (inFile, MMap::Read);
-      }
-      LOG_INFO_STR("Input column " << inColumnName << " maps to: " << inFile);
-    }
-  }
-  
-  
-  if (! outColumnName.empty()) {
-    if (tab.isNull()) {
-      tab = Table(itsMSName);
-    }
-    
-    string outFile = getFileForColumn(outColumnName);
-    if (itsOutDataMap == 0 || outFile.empty() || itsOutDataMap->getFileName() != outFile) {
-      if (!tab.tableDesc().isColumn(outColumnName)) {
-//    addDataColumn (tab, outColumnName, outFile);
-        addDataColumn (tab, outColumnName);
-        outFile = getFileForColumn(outColumnName);
-      }
-      ASSERTSTR(!outFile.empty(), "Column " << outColumnName << " does not exist or has non-standard storage manager.");
-      
-      delete itsOutDataMap;
-      itsOutDataMap = 0;
-      itsOutDataMap = new MMap (outFile, MMap::ReWr);
-      
-      LOG_INFO_STR("Output column " << outColumnName << " maps to: " << outFile);
+    // Remove the funklets from all parms.
+    for (MeqParmGroup::iterator it = itsParmGroup.begin();
+        it != itsParmGroup.end();
+        ++it)
+    {
+        it->second.removeFunklets();
     }
-  }
 }
 
 
-void Prediffer::addDataColumn(Table& tab, const string& columnName)
+void Prediffer::initializeSolveDomains(pair<size_t, size_t> size)
 {
-  ASSERT(itsColumns.find(columnName) == itsColumns.end());
-  
-  ArrayColumnDesc<Complex> resCol(columnName, IPosition(2, itsNCorr, itsNrChan), ColumnDesc::FixedShape);
-  String stManName = "Tiled_"+columnName;
-  TiledColumnStMan tiledRes(stManName, IPosition(3, itsNCorr, itsNrChan, 1));
-  
-  tab.reopenRW();
-  tab.addColumn (resCol, tiledRes);
-  tab.flush();
-  
-  /*
-    Find out which datamanager the new column is in.
-  */
-  Record dminfo = tab.dataManagerInfo();
-  for (uint i=0; i<dminfo.nfields(); ++i)
-  {
-    const Record& dm = dminfo.subRecord(i);
-    if (dm.asString("NAME") == stManName)
+    // Need to implement some way to select local solve domains
+    // from global solve domains, see initSolvableParms().
+    size_t nFreqDomains =
+        ceil(itsChunkData->freq.size() / static_cast<double>(size.first));
+    size_t nTimeDomains =
+        ceil(itsChunkData->time.size() / static_cast<double>(size.second));
+    size_t nSolveDomains = nFreqDomains * nTimeDomains;
+
+    cout << "freq.size(): " << itsChunkData->freq.size() << " #domains: "
+        << nFreqDomains << endl;
+    cout << "time.size(): " << itsChunkData->time.size() << " #domains: "
+        << nTimeDomains << endl;
+
+    itsContext.domainSize = size;
+    itsContext.domainCount = make_pair(nFreqDomains, nTimeDomains);
+    itsContext.domains.resize(nSolveDomains);
+
+    // Generate solve domains.
+    // TODO: Update interface of MeqParmFunklet so we can lose the solveDomains
+    // vector and the domainUnknownCount vector below.
+    vector<MeqDomain> solveDomains(nSolveDomains);
+    vector<int> domainUnknownCount(nSolveDomains, 0);
+
+    size_t idx = 0, tstart = 0;
+    for(size_t tdomain = 0; tdomain < nTimeDomains; ++tdomain)
     {
-      ostringstream os;
-      os << itsMSName << "/table.f" << i << "_TSM0";
-      itsColumns[columnName] = os.str();
-      break;
-    }
-  }
-}
+        size_t tend = tstart + size.second - 1;
+        if(tend >= itsChunkData->time.size())
+            tend = itsChunkData->time.size() - 1;
 
-//-----------------------[ Parameter Access ]-----------------------//
+        size_t fstart = 0;
+        for(size_t fdomain = 0; fdomain < nFreqDomains; ++fdomain)
+        {
+            size_t fend = fstart + size.first - 1;
+            if(fend >= itsChunkData->freq.size())
+                fend = itsChunkData->freq.size() - 1;
 
-void Prediffer::readParms()
-{
-  // Read all parms for this domain into a single map.
-  itsParmValues.clear();
-  vector<string> emptyvec;
-  LOFAR::ParmDB::ParmDomain pdomain(itsWorkDomain.startX(), itsWorkDomain.endX(),
-                 itsWorkDomain.startY(), itsWorkDomain.endY());
-  itsMEP->getValues (itsParmValues, emptyvec, pdomain);
-  itsGSMMEP->getValues (itsParmValues, emptyvec, pdomain);
-  // Remove the funklets from all parms.
-  for (MeqParmGroup::iterator iter = itsParmGroup.begin();
-       iter != itsParmGroup.end();
-       ++iter)
-  {
-    iter->second.removeFunklets();
-  }
-}
+            itsContext.domains[idx].domain =
+                MeqDomain(itsChunkData->freq.lower(fstart),
+                    itsChunkData->freq.upper(fend),
+                    itsChunkData->time.lower(tstart),
+                    itsChunkData->time.upper(tend));
 
+            solveDomains[idx] = itsContext.domains[idx].domain;
 
-void Prediffer::initializeSolveDomains(const vector<MeqDomain> &globalSolveDomains)
-{
-    // Need to implement some way to select local solve domains
-    // from global solve domains, see initSolvableParms().    
-    const vector<MeqDomain> solveDomains = globalSolveDomains;
-    itsSolveDomainDescriptors.clear();
-    itsSolveDomainDescriptors.resize(solveDomains.size());
-
-    itsNrPert = 0;
-    itsNrScids.resize(solveDomains.size());
-    fill(itsNrScids.begin(), itsNrScids.end(), 0);
-    for (MeqParmGroup::iterator iter = itsParmGroup.begin();
-         iter != itsParmGroup.end();
-         ++iter)
+            fstart += size.first;
+            ++idx;
+        }
+        tstart += size.second;
+    }
+
+    // Initialize solve domain meta data (e.g. number of unknowns, unknown
+    // index, etc.)
+    int nDerivatives = 0;
+    for(MeqParmGroup::iterator it = itsParmGroup.begin();
+        it != itsParmGroup.end();
+        ++it)
     {
-        // Determine maximal number of solvable coefficients over all solve domains
-        // for this parameter.
-        int max = iter->second.initDomain(solveDomains, itsNrPert, itsNrScids);
+        // Determine maximal number of unknowns over all solve domains for this
+        // parameter.
+        int max = it->second.initDomain(solveDomains, nDerivatives,
+            domainUnknownCount);
+
         if(max > 0)
         {
-            const vector<MeqFunklet*>& funklets = iter->second.getFunklets();
-            ASSERT(funklets.size() == solveDomains.size());
-            for(size_t i = 0; i < solveDomains.size(); ++i)
+            const vector<MeqFunklet*>& funklets = it->second.getFunklets();
+            ASSERT(funklets.size() == nSolveDomains);
+
+            for(size_t i = 0; i < nSolveDomains; ++i)
             {
-                itsSolveDomainDescriptors[i].domain = solveDomains[i];
-                itsSolveDomainDescriptors[i].parameters.push_back(iter->second);
-                itsSolveDomainDescriptors[i].unknownIndex.push_back(itsSolveDomainDescriptors[i].unknowns.size());
+                SolveDomainDescriptor &domain = itsContext.domains[i];
+                domain.parameters.push_back(it->second);
+                domain.unknownIndex.push_back(domain.unknowns.size());
 
                 const MeqMatrix &coeff = funklets[i]->getCoeff();
                 const vector<bool> &mask = funklets[i]->getSolvMask();
-                for(unsigned int j = 0; j < coeff.nelements(); j++)
+                for(size_t j = 0; j < coeff.nelements(); ++j)
                 {
                     if(mask[j])
-                        itsSolveDomainDescriptors[i].unknowns.push_back(coeff.doubleStorage()[j]);
+                        domain.unknowns.push_back(coeff.doubleStorage()[j]);
                 }
             }
         }
     }
-  
-    // Determine the fitter indices for the frequency and time axis.
-    // First check if the (local) solve domains are ordered and regular.
-    // Start with finding the number of frequency intervals.
-    for (itsFreqNrFit=1; itsFreqNrFit<solveDomains.size(); itsFreqNrFit++) {
-        if (solveDomains[itsFreqNrFit].startX() <
-        solveDomains[itsFreqNrFit-1].endX()) {
-        break;
-        }
-    }
-    // Now check if regular in frequency and time.
-    uint timeNrFit = solveDomains.size() / itsFreqNrFit;
-    ASSERT (timeNrFit*itsFreqNrFit == solveDomains.size());
-    for (uint inxt=0; inxt<timeNrFit; inxt++) {
-        const MeqDomain& first = solveDomains[inxt*itsFreqNrFit];
-        for (uint inxf=1; inxf<itsFreqNrFit; inxf++) {
-        const MeqDomain& cur = solveDomains[inxt*itsFreqNrFit + inxf];
-        ASSERT (cur.startY() == first.startY()  &&  cur.endY() == first.endY());
-        }
-    }
-    for (uint inxf=0; inxf<itsFreqNrFit; inxf++) {
-        const MeqDomain& first = solveDomains[inxf];
-        for (uint inxt=1; inxt<timeNrFit; inxt++) {
-        const MeqDomain& cur = solveDomains[inxt*itsFreqNrFit + inxf];
-        ASSERT (cur.startX() == first.startX()  &&  cur.endX() == first.endX());
-        }
-    }
-    // Determine for each frequency point to which fitter it belongs.
-    // For the time axis it is determined by nextDataChunk.
-    int nrchan = itsLastChan-itsFirstChan+1;
-    itsFreqFitInx.resize (nrchan);
-    double step = itsWorkDomain.sizeX() / nrchan;
-    double freq = itsWorkDomain.startX() + step / 2;
-    int interv = 0;
-    for (int i=0; i<nrchan; i++) {
-        if (freq > solveDomains[interv].endX()) {
-        interv++;
-        }
-        itsFreqFitInx[i] = interv;
-        freq += step;
+    itsContext.derivativeCount = nDerivatives;
+}
+
+
+void Prediffer::clearSolvableParms()
+{
+    LOG_TRACE_FLOW( "clearSolvableParms" );
+    for (MeqParmGroup::iterator it = itsParmGroup.begin();
+        it != itsParmGroup.end();
+        ++it)
+    {
+        it->second.setSolvable(false);
     }
 }
 
 
-void Prediffer::initSolvableParms (const vector<MeqDomain>& solveDomains)
+//-----------------------[ Computation ]-----------------------//
+void Prediffer::process(bool useFlags, bool precalc, bool derivatives,
+    pair<size_t, size_t> start, pair<size_t, size_t> end,
+    BaselineProcessor processor, void *arguments)
 {
-  itsParmData.set (solveDomains, itsWorkDomain);
-  const vector<MeqDomain>& localSolveDomains = itsParmData.getDomains();
+    // Determine if perturbed values have to be calculated.
+    int nPerturbedValues = derivatives ? itsContext.derivativeCount : 0;
 
-  itsSolveDomains = localSolveDomains;
+    // Get frequency / time grid information.
+    int nChannels = end.first - start.first + 1;
+    int nTimeslots = end.second - start.second + 1;
 
-  itsNrPert = 0;
-  itsNrScids.resize (localSolveDomains.size());
-  fill (itsNrScids.begin(), itsNrScids.end(), 0);
-  for (MeqParmGroup::iterator iter = itsParmGroup.begin();
-       iter != itsParmGroup.end();
-       ++iter)
-  {
-    int nr = iter->second.initDomain (localSolveDomains,
-                      itsNrPert, itsNrScids);
-    if (nr > 0) {
-      itsParmData.parms().push_back (ParmData(iter->second.getName(),
-                          iter->second.getParmDBSeqNr(),
-                          iter->second.getFunklets()));
-    }
-  }
-  // Determine the fitter indices for the frequency and time axis.
-  // First check if the (local) solve domains are ordered and regular.
-  // Start with finding the number of frequency intervals.
-  for (itsFreqNrFit=1; itsFreqNrFit<localSolveDomains.size(); itsFreqNrFit++) {
-    if (localSolveDomains[itsFreqNrFit].startX() <
-    localSolveDomains[itsFreqNrFit-1].endX()) {
-      break;
-    }
-  }
-  // Now check if regular in frequency and time.
-  uint timeNrFit = localSolveDomains.size() / itsFreqNrFit;
-  ASSERT (timeNrFit*itsFreqNrFit == localSolveDomains.size());
-  for (uint inxt=0; inxt<timeNrFit; inxt++) {
-    const MeqDomain& first = localSolveDomains[inxt*itsFreqNrFit];
-    for (uint inxf=1; inxf<itsFreqNrFit; inxf++) {
-      const MeqDomain& cur = localSolveDomains[inxt*itsFreqNrFit + inxf];
-      ASSERT (cur.startY() == first.startY()  &&  cur.endY() == first.endY());
-    }
-  }
-  for (uint inxf=0; inxf<itsFreqNrFit; inxf++) {
-    const MeqDomain& first = localSolveDomains[inxf];
-    for (uint inxt=1; inxt<timeNrFit; inxt++) {
-      const MeqDomain& cur = localSolveDomains[inxt*itsFreqNrFit + inxf];
-      ASSERT (cur.startX() == first.startX()  &&  cur.endX() == first.endX());
+    // NOTE: Temporary vector should be removed after MNS overhaul.
+    vector<double> timeAxis(nTimeslots + 1);
+    for(size_t i = 0; i < nTimeslots; ++i)
+        timeAxis[i] = itsChunkData->time.lower(start.second + i);
+    timeAxis[nTimeslots] = itsChunkData->time.upper(end.second);
+
+    // Initialize the ComplexArr pool with the most frequently used size.
+    uint64 defaultPoolSize = itsMeasurement->getChannelCount() * nTimeslots;
+    MeqMatrixComplexArr::poolDeactivate();
+    MeqMatrixRealArr::poolDeactivate();
+    MeqMatrixComplexArr::poolActivate(defaultPoolSize);
+    MeqMatrixRealArr::poolActivate(defaultPoolSize);
+
+    // Create a request.
+    MeqDomain domain(itsChunkData->freq.lower(start.first),
+        itsChunkData->freq.upper(end.first),
+        itsChunkData->time.lower(start.second),
+        itsChunkData->time.upper(end.second));
+
+    MeqRequest request(domain, nChannels, timeAxis, nPerturbedValues);
+    request.setOffset(start);
+
+    // Precalculate if required.
+    // TODO: Fix this when doing a correct!
+    if(precalc)
+        itsModel->precalculate(request);
+
+/************** DEBUG DEBUG DEBUG **************/
+/*
+    cout << "Processing correlations: ";
+    copy(itsContext.correlations.begin(), itsContext.correlations.end(),
+        ostream_iterator<size_t>(cout, " "));
+    cout << endl;
+
+    cout << "Processing baselines:" << endl;
+    for(set<baseline_t>::const_iterator it = itsContext.baselines.begin();
+        it != itsContext.baselines.end();
+        ++it)
+    {
+        cout << it->first << " - " << it->second << endl;
     }
-  }
-  // Determine for each frequency point to which fitter it belongs.
-  // For the time axis it is determined by nextDataChunk.
-  int nrchan = itsLastChan-itsFirstChan+1;
-  itsFreqFitInx.resize (nrchan);
-  double step = itsWorkDomain.sizeX() / nrchan;
-  double freq = itsWorkDomain.startX() + step / 2;
-  int interv = 0;
-  for (int i=0; i<nrchan; i++) {
-    if (freq > localSolveDomains[interv].endX()) {
-      interv++;
+*/
+/************** DEBUG DEBUG DEBUG **************/
+
+#pragma omp parallel
+    {
+#pragma omp for schedule(dynamic)
+    // Process all selected baselines.
+    for(set<baseline_t>::const_iterator it = itsContext.baselines.begin();
+        it != itsContext.baselines.end();
+        ++it)
+    {
+//        LOG_DEBUG_STR("Processing baseline " << it->first << " - "
+//            << it->second);
+
+#if defined _OPENMP
+        size_t thread = omp_get_thread_num();
+#else
+        size_t thread = 0;
+#endif
+        // Process baseline.
+        (this->*processor)
+            (thread, arguments, itsChunkData, start, request, *it, false);
+    }
+    } // omp parallel
+}
+
+
+void Prediffer::predictBaseline(int, void*, VisData::Pointer chunk,
+    pair<size_t, size_t> offset, const MeqRequest& request, baseline_t baseline,
+    bool showd)
+{
+    // Do the actual correct.
+    itsPredTimer.start();
+    MeqJonesResult jresult = itsModel->evaluate(baseline, request);
+    itsPredTimer.stop();
+
+    itsEqTimer.start();
+    // Put the results in a single array for easier handling.
+    const double *resultRe[4], *resultIm[4];
+    jresult.getResult11().getValue().dcomplexStorage(resultRe[0],
+        resultIm[0]);
+    jresult.getResult12().getValue().dcomplexStorage(resultRe[1],
+        resultIm[1]);
+    jresult.getResult21().getValue().dcomplexStorage(resultRe[2],
+        resultIm[2]);
+    jresult.getResult22().getValue().dcomplexStorage(resultRe[3],
+        resultIm[3]);
+
+    // Get information about request grid.
+    size_t nChannels = request.nx();
+    size_t nTimeslots = request.ny();
+
+    // Get baseline index.
+    size_t basel = chunk->getBaselineIndex(baseline);
+
+    // Copy the data to the right location.
+    for(size_t tslot = offset.second;
+        tslot < offset.second + nTimeslots;
+        ++tslot)
+    {
+        for(set<pair<size_t, size_t> >::const_iterator it =
+                itsContext.polarizations.begin();
+            it != itsContext.polarizations.end();
+            ++it)
+        {
+            size_t pol = it->first;
+
+            const double* re = resultRe[it->second];
+            const double* im = resultIm[it->second];
+
+            for(size_t chan = 0; chan < nChannels; ++chan)
+            {
+                chunk->vis_data[basel][tslot][offset.first + chan][pol] =
+                    makefcomplex(re[chan], im[chan]);
+            }
+
+            resultRe[pol] += nChannels;
+            resultIm[pol] += nChannels;
+        }
     }
-    itsFreqFitInx[i] = interv;
-    freq += step;
-  }
+    itsEqTimer.stop();
 }
 
-void Prediffer::clearSolvableParms()
+
+void Prediffer::subtractBaseline(int, void*, VisData::Pointer chunk,
+    pair<size_t, size_t> offset, const MeqRequest& request, baseline_t baseline,
+    bool showd)
 {
-  LOG_TRACE_FLOW( "clearSolvableParms" );
-  for (MeqParmGroup::iterator iter = itsParmGroup.begin();
-       iter != itsParmGroup.end();
-       ++iter)
-  {
-    iter->second.setSolvable(false);
-  }
-}
+    // Do the actual correct.
+    itsPredTimer.start();
+    MeqJonesResult jresult = itsModel->evaluate(baseline, request);
+    itsPredTimer.stop();
 
+    itsEqTimer.start();
+    // Put the results in a single array for easier handling.
+    const double *resultRe[4], *resultIm[4];
+    jresult.getResult11().getValue().dcomplexStorage(resultRe[0],
+        resultIm[0]);
+    jresult.getResult12().getValue().dcomplexStorage(resultRe[1],
+        resultIm[1]);
+    jresult.getResult21().getValue().dcomplexStorage(resultRe[2],
+        resultIm[2]);
+    jresult.getResult22().getValue().dcomplexStorage(resultRe[3],
+        resultIm[3]);
+
+    // Get information about request grid.
+    size_t nChannels = request.nx();
+    size_t nTimeslots = request.ny();
+
+    // Get baseline index.
+    size_t basel = chunk->getBaselineIndex(baseline);
+
+    // Copy the data to the right location.
+    for(size_t tslot = offset.second;
+        tslot < offset.second + nTimeslots;
+        ++tslot)
+    {
+        for(set<pair<size_t, size_t> >::const_iterator it =
+                itsContext.polarizations.begin();
+            it != itsContext.polarizations.end();
+            ++it)
+        {
+            size_t pol = it->first;
 
-//-----------------------[ Computation ]-----------------------//
+            const double* re = resultRe[it->second];
+            const double* im = resultIm[it->second];
 
+            for(size_t chan = 0; chan < nChannels; ++chan)
+            {
+                chunk->vis_data[basel][tslot][offset.first + chan][pol] -=
+                    makefcomplex(re[chan], im[chan]);
+            }
 
-// Currently this function always returns all data in the work domain.
-// In the future it can be made smarter and process less if the work domain
-// is very large.
-bool Prediffer::nextDataChunk (bool useFitters)
-{
-  if (itsNrTimesDone >= itsNrTimes) {
-    return false;
-  }
-  /// For the time being all times of the work domain are mapped in.
-  int nt = itsNrTimes;
-  int st = itsNrTimesDone;
-  // Map the part of the file matching the given times.
-//  BBSTest::ScopedTimer mapTimer("P:file-mapping");
-
-  int64 nrValues = nt * itsMSMapInfo.timeSize();
-  int64 startOffset = itsTimeIndex * itsMSMapInfo.timeSize();
-  if (itsInDataMap) {
-    itsInDataMap->mapFile(startOffset*sizeof(fcomplex),
-              nrValues*sizeof(fcomplex));
-    itsMSMapInfo.setInData(static_cast<fcomplex*>(itsInDataMap->getStart()));
-  }
-  if (itsOutDataMap) {
-    itsOutDataMap->mapFile(startOffset*sizeof(fcomplex),
-               nrValues*sizeof(fcomplex));
-    itsMSMapInfo.setOutData(static_cast<fcomplex*>(itsOutDataMap->getStart()));
-  }
-  // Map the correct flags subset (this time interval).
-  itsFlagsMap->mapFile(startOffset, nrValues);
-  // Map the weights.
-  ///  itsWeightMap->mapFile(..,..);
-  // Fill the time vector.
-  itsChunkTimes.resize (nt+1);
-  for (int i=0; i<nt; ++i) {
-    itsChunkTimes[i] = itsMSDesc.times[itsTimeIndex + st + i] -
-                       itsMSDesc.exposures[itsTimeIndex + st + i] / 2;
-  }
-  itsChunkTimes[nt] = itsMSDesc.times[itsTimeIndex + st + nt-1] +
-                      itsMSDesc.exposures[itsTimeIndex + st + nt-1] / 2;
-  itsMSMapInfo.setTimes (st, nt);
-  itsNrTimesDone += nt;
-  if (useFitters) {
-    // Determine for each time point to which fitter it belongs.
-//    const vector<MeqDomain>& localSolveDomains = itsParmData.getDomains();
-    const vector<MeqDomain>& localSolveDomains = itsSolveDomains;
-    itsTimeFitInx.resize (nt);
-    uint interv = 0;
-    for (int i=0; i<nt; i++) {
-      double time = itsMSDesc.times[itsTimeIndex + st + i];
-      while (time > localSolveDomains[interv*itsFreqNrFit].endY()) {
-    interv++;
-    DBGASSERT (interv < localSolveDomains.size()/itsFreqNrFit);
-      }
-      itsTimeFitInx[i] = interv;
+            resultRe[pol] += nChannels;
+            resultIm[pol] += nChannels;
+        }
     }
-  }
-  return true;
+    itsEqTimer.stop();
 }
 
-void Prediffer::processData (bool useFlags, bool preCalc, bool calcDeriv,
-                 ProcessFuncBL pfunc,
-                 void* arg)
+
+void Prediffer::correctBaseline(int, void*, VisData::Pointer chunk,
+    pair<size_t, size_t> offset, const MeqRequest& request, baseline_t baseline,
+    bool showd)
 {
-  // Map the correct input and output file (if needed).
-  mapDataFiles (itsInDataColumn, itsOutDataColumn);
-  // Calculate frequency axis info.
-  int nrchan = itsLastChan-itsFirstChan+1;
-  double startFreq = itsStartFreq + itsFirstChan*itsStepFreq;
-  double endFreq   = itsStartFreq + (itsLastChan+1)*itsStepFreq;
-  // Add offset for dd (band) and channel.
-  unsigned int freqOffset = itsFirstChan*itsNCorr + itsMSMapInfo.ddOffset();
-  // Determine if perturbed values have to be calculated.
-  int nrpert = calcDeriv ? itsNrPert:0;
-  // Loop through the domain of the data to be processed.
-  // Process as much data as possible (hopefully everything).
-  itsNrTimesDone = 0;
-  while (nextDataChunk(nrpert>0)) {
-    int nrtimes = itsMSMapInfo.nrTimes();
-    // Initialize the ComplexArr pool with the most frequently used size
-    // itsNrChan is the number of frequency channels
-    MeqMatrixComplexArr::poolDeactivate();
-    MeqMatrixRealArr::poolDeactivate();
-    MeqMatrixComplexArr::poolActivate(itsNrChan * nrtimes);
-    MeqMatrixRealArr::poolActivate(itsNrChan * nrtimes);
+    // Do the actual correct.
+    itsPredTimer.start();
+    MeqJonesResult jresult = itsModel->evaluate(baseline, request);
+    itsPredTimer.stop();
 
-    // Size the thread private flag buffers.
-    if (useFlags) {
-      for (int i=0; i<itsNthread; ++i) {
-    itsFlagVecs[i].resize (nrtimes*nrchan*itsNCorr);
-      }
-    }
-    fcomplex* inDataStart  = itsMSMapInfo.inData();
-    fcomplex* outDataStart = itsMSMapInfo.outData();
-    void* flagStart = itsFlagsMap->getStart();
-    int flagStartBit = itsFlagsMap->getStartBit();
+    itsEqTimer.start();
+    // Put the results in a single array for easier handling.
+    const double *resultRe[4], *resultIm[4];
+    jresult.getResult11().getValue().dcomplexStorage(resultRe[0],
+        resultIm[0]);
+    jresult.getResult12().getValue().dcomplexStorage(resultRe[1],
+        resultIm[1]);
+    jresult.getResult21().getValue().dcomplexStorage(resultRe[2],
+        resultIm[2]);
+    jresult.getResult22().getValue().dcomplexStorage(resultRe[3],
+        resultIm[3]);
 
-    // Create a request.
-    MeqDomain domain(startFreq, endFreq, itsChunkTimes[0],
-             itsChunkTimes[itsChunkTimes.size()-1]);
-    MeqRequest request(domain, nrchan, itsChunkTimes, nrpert);
-    request.setFirstX (itsFirstChan);
-    // Loop through all baselines.
-    //static NSTimer timer("Prediffer::fillFitters", true);
-    //timer.start();
-    if (preCalc) {
-        precalcNodes (request);
-    }
+    // Get information about request grid.
+    size_t nChannels = request.nx();
+    size_t nTimeslots = request.ny();
 
-    // Loop through all baselines and fill its equations if selected.
-#pragma omp parallel
+    // Get baseline index.
+    size_t basel = chunk->getBaselineIndex(baseline);
+
+    // Copy the data to the right location.
+    for(size_t tslot = offset.second;
+        tslot < offset.second + nTimeslots;
+        ++tslot)
     {
-#pragma omp for schedule(dynamic)
-      for (uint blindex=0; blindex<itsBLInx.size(); ++blindex) {
-    int bl = itsBLInx[blindex];
-    // Get pointer to correct data part.
-    unsigned int offset = freqOffset + bl*itsNrChan*itsNCorr;
-    fcomplex* idata = inDataStart + offset;
-    fcomplex* odata = outDataStart + offset;
-    // Convert the flag bits to bools.
-    ///   if (ant1==8&&ant2==11&&tStep<5) {
-      ///cout << "flagmap: start="<<flagStart<<" sbit="<<flagStartBit
-      /// << " offs="<<offset<<endl;
-      ///     }
-#if defined _OPENMP
-    int threadNr = omp_get_thread_num();
-#else
-    int threadNr = 0;
-#endif
-    // If needed, convert flag bits to bools.
-    bool* flags = 0;
-    if (useFlags) {
-      flags = &itsFlagVecs[threadNr][0];
-      for (int i=0; i<itsMSMapInfo.nrTimes(); ++i) {
-        bitToBool (flags+i*nrchan*itsNCorr, flagStart, nrchan*itsNCorr,
-               offset + flagStartBit);
-        offset += itsMSMapInfo.timeSize();
-      }
-    }
-    // Call the given member function.
-    (this->*pfunc) (threadNr, arg, idata, odata, flags,
-            request, blindex, false);
-            ///request, blindex, itsAnt1[bl]==4&&itsAnt2[bl]==8);
-      }
-    } // end omp parallel
-      //timer.stop();
-  }
-}
+        for(set<pair<size_t, size_t> >::const_iterator it =
+                itsContext.polarizations.begin();
+            it != itsContext.polarizations.end();
+            ++it)
+        {
+            size_t pol = it->first;
 
-void Prediffer::fillFitters (vector<casa::LSQFit>& fitters)
-{
-  // Find all nodes to be precalculated.
-  setPrecalcNodes (itsExpr);
-  // Initialize the fitters.
-  int nfitter = itsNrScids.size();
-  fitters.resize (nfitter);
-  
-#ifdef COMPUTE_SQUARED_ERROR  
-  itsSquaredErrorReal.resize(nfitter);
-  itsSquaredErrorImag.resize(nfitter);
-  fill(itsSquaredErrorReal.begin(), itsSquaredErrorReal.end(), 0.0);
-  fill(itsSquaredErrorImag.begin(), itsSquaredErrorImag.end(), 0.0);
-#endif
-    
-  // Create thread private fitters for parallel execution.
-  vector<vector<LSQFit*> > threadPrivateFitters(itsNthread);
-  for (int i=0; i<itsNthread; ++i) {
-    threadPrivateFitters[i].resize (nfitter);
-  }
-  for (int i=0; i<nfitter; ++i) {
-    fitters[i].set (itsNrScids[i]);
-    threadPrivateFitters[0][i] = &fitters[i];
-    for (int j=1; j<itsNthread; j++) {
-      threadPrivateFitters[j][i] = new LSQFit(itsNrScids[i]);
-    }
-  }
-  // Size the thread private buffers.
-  ///int nrchan = itsLastChan-itsFirstChan+1;
-  for (int i=0; i<itsNthread; ++i) {
-    itsResultVecs[i].resize (2*itsNrPert);
-    itsDiffVecs[i].resize (3*itsNrPert);
-    itsIndexVecs[i].resize (itsNrPert);
-    ///    itsOrdFlagVecs[i].resize (2*nrchan);
-  }
-  // Process the data and use the flags.
-  processData (true, true, true,
-                            &Prediffer::fillEquation, &threadPrivateFitters);
-  // Merge the thread-specific fitters into the main ones.
-  for (int j=1; j<itsNthread; ++j) {
-    for (int i=0; i<nfitter; ++i) {
-      fitters[i].merge (*threadPrivateFitters[j][i]);
-      delete threadPrivateFitters[j][i];
+            const double* re = resultRe[it->second];
+            const double* im = resultIm[it->second];
+
+            for(size_t chan = 0; chan < nChannels; ++chan)
+            {
+                chunk->vis_data[basel][tslot][offset.first + chan][pol] =
+                    makefcomplex(re[chan], im[chan]);
+            }
+
+            resultRe[pol] += nChannels;
+            resultIm[pol] += nChannels;
+        }
     }
-  }
-  
-#ifdef COMPUTE_SQUARED_ERROR  
-  for(int i = 0; i < nfitter; ++i)
-  {
-    LOG_DEBUG_STR(
-        "SquaredError: domain: " <<
-        i <<
-        " real: " <<
-        itsSquaredErrorReal[i] <<
-        " imaginary: " <<
-        itsSquaredErrorImag[i]);
-  }
-#endif
-  
-  LOG_DEBUG_STR("Predict: " << itsPredTimer);
-  LOG_DEBUG_STR("Construct equations: " << itsEqTimer);
-  itsPredTimer.reset();
-  itsEqTimer.reset();
-}
+    itsEqTimer.stop();
+}
+
+
+void Prediffer::generateBaseline(int threadnr, void* arguments,
+    VisData::Pointer chunk, pair<size_t, size_t> offset,
+    const MeqRequest& request, baseline_t baseline, bool showd)
+{
+    // Check precondition.
+    ASSERT(offset.first % itsContext.domainSize.first == 0);
+    ASSERT(offset.second % itsContext.domainSize.second == 0);
+
+    // Get the solver objects.
+    vector<casa::LSQFit*> &solvers =
+        (*static_cast<vector<vector<casa::LSQFit*> >*>(arguments))[threadnr];
+
+    // Get pointers to thread specific data structures.
+    // TODO: Get rid of ghastly pointer arithmetic.
+    uint* indices = &(itsIndexVecs[threadnr][0]);
+    const double** pertReal = &(itsResultVecs[threadnr][0]);
+    const double** pertImag = pertReal + itsContext.derivativeCount;
+    double* invPert = &(itsDiffVecs[threadnr][0]);
+    double* resultr = invPert + itsContext.derivativeCount;
+    double* resulti = resultr + itsContext.derivativeCount;
+
+    // Do the actual predict.
+    itsPredTimer.start();
+    MeqJonesResult jresult = itsModel->evaluate(baseline, request);
+    itsPredTimer.stop();
+
+    itsEqTimer.start();
+    // Put the results in a single array for easier handling.
+    const MeqResult *predictResults[4];
+    predictResults[0] = &(jresult.getResult11());
+    predictResults[1] = &(jresult.getResult12());
+    predictResults[2] = &(jresult.getResult21());
+    predictResults[3] = &(jresult.getResult22());
+
+    // Get information about request grid.
+    size_t nChannels = request.nx();
+    size_t nTimeslots = request.ny();
+
+    // Get baseline index.
+    size_t basel = chunk->getBaselineIndex(baseline);
+
+    // To avoid having to use large temporary arrays, step through the
+    // data by timestep and correlation.
+    uint nreq=0;
+    for(set<pair<size_t, size_t> >::const_iterator it =
+            itsContext.polarizations.begin();
+        it != itsContext.polarizations.end();
+        ++it)
+    {
+        size_t pol = it->first;
+
+        // Get the results for this correlation.
+        const MeqResult &tcres = *predictResults[it->second];
+
+        // Get pointers to the main data.
+        const MeqMatrix &val = tcres.getValue();
+        const double *realVals;
+        const double *imagVals;
+        val.dcomplexStorage(realVals, imagVals);
+
+        // Determine which parameters have derivatives and keep that info.
+        // E.g. when solving for station parameters, only a few parameters
+        // per baseline have derivatives.
+        // Note that this is the same for the entire work domain.
+        // Also get pointers to the perturbed values.
+        int nrParamsFound = 0;
+        for (int scinx = 0; scinx < itsContext.derivativeCount; ++scinx)
+        {
+            if (tcres.isDefined(scinx))
+            {
+                indices[nrParamsFound] = scinx;
+                const MeqMatrix& valp = tcres.getPerturbedValue(scinx);
+                valp.dcomplexStorage (pertReal[nrParamsFound],
+                    pertImag[nrParamsFound]);
+                invPert[nrParamsFound] = 1. / tcres.getPerturbation(scinx,0);
+                ++nrParamsFound;
+            }
+        }
 
-void Prediffer::correctData()
-{
-  // Find all nodes to be precalculated.
-  setPrecalcNodes (itsCorrExpr);
-  processData (false, true, false,
-           &Prediffer::correctBL, 0);
-  ///  if (flush) {
-    ///    itsOutDataMap->flush();
-    ///  }
-    
-  LOG_DEBUG_STR("Read/Correct: " << itsPredTimer);
-  LOG_DEBUG_STR("Write: " << itsEqTimer);
-  itsPredTimer.reset();
-  itsEqTimer.reset();
-}
+        if (nrParamsFound > 0)
+        {
+            for(size_t tslot = offset.second;
+                tslot < offset.second + nTimeslots;
+                ++tslot)
+            {
+/************** DEBUG DEBUG DEBUG **************/
+//                if (showd)
+//                {
+//                    showData(corr, sdch, inc, nrchan, cflags, cdata,
+//                        realVals, imagVals);
+//                }
+/************** DEBUG DEBUG DEBUG **************/
+
+                // Compute relative solver index (time part).
+                size_t solverIndexTime =
+                    ((tslot - offset.second) / itsContext.domainSize.second)
+                        * itsContext.domainCount.first;
+
+                // Loop through all channels.
+                // Form two equations for each unflagged data point.
+                for (int ch = offset.first;
+                    ch < offset.first + nChannels;
+                    ++ch)
+                {
+                    // Compute relative solver index.
+                    size_t solverIndex = solverIndexTime +
+                        (ch - offset.first) / itsContext.domainSize.first;
 
-void Prediffer::subtractData()
-{
-  // Find all nodes to be precalculated.
-  setPrecalcNodes (itsExpr);
-  processData (false, true, false,
-           &Prediffer::subtractBL, 0);
-  ///  if (flush) {
-    ///    itsOutDataMap->flush();
-    ///  }
-  
-  LOG_DEBUG_STR("Predict: " << itsPredTimer);
-  LOG_DEBUG_STR("Read/Subtract/Write: " << itsEqTimer);
-  itsPredTimer.reset();
-  itsEqTimer.reset();
-}
+                    if (!chunk->vis_flag[basel][tslot][ch][pol])
+                    {
+                        // Compute right hand side of the equation pair.
+                        double diffr =
+                            real(chunk->vis_data[basel][tslot][ch][pol])
+                                - *realVals;
+                        double diffi =
+                            imag(chunk->vis_data[basel][tslot][ch][pol])
+                                - *imagVals;
+
+                        #ifdef COMPUTE_SQUARED_ERROR
+                        itsSquaredErrorReal[solverIndex] += diffr*diffr;
+                        itsSquaredErrorImag[solverIndex] += diffi*diffi;
+                        #endif
+
+                        // Compute left hand side of the equation pair.
+                        for(int scinx = 0; scinx < nrParamsFound; ++scinx)
+                        {
+                            // Approximate the derivative for real and imag
+                            // part.
+                            double invp = invPert[scinx];
+                            resultr[scinx] = (*pertReal[scinx] - *realVals)
+                                * invp;
+                            resulti[scinx] = (*pertImag[scinx] - *imagVals)
+                                * invp;
+                        }
 
-void Prediffer::writePredictedData()
-{
-  // Find all nodes to be precalculated.
-  setPrecalcNodes (itsExpr);
-  processData (false, true, false,
-           &Prediffer::predictBL, 0);
+                        // Now add the equations to the correct fitter
+                        // object.
+                        if (nrParamsFound != itsContext.derivativeCount)
+                        {
+                            solvers[solverIndex]->makeNorm(
+                                itsContext.derivativeCount, indices, resultr,
+                                1.0, diffr);
+
+                            solvers[solverIndex]->makeNorm(
+                                itsContext.derivativeCount, indices, resulti,
+                                1.0, diffi);
+                        }
+                        else
+                        {
+                            solvers[solverIndex]->makeNorm(resultr, 1.0, diffr);
+                            solvers[solverIndex]->makeNorm(resulti, 1.0, diffi);
+                        }
+
+/************** DEBUG DEBUG DEBUG **************/
+/*
+                        if (showd)
+                        {
+                            cout << "eq"<<corr<<" ch " << 2*ch << " diff "
+                                << diffr;
+                            for (int ii=0; ii<nrParamsFound; ii++)
+                                cout << ' '<<resultr[ii];
+
+                            cout << endl;
+                            cout << "eq"<<corr<<" ch " << 2*ch+1 << " diff "
+                                << diffi;
+
+                            for (int ii=0; ii<nrParamsFound; ii++)
+                                cout << ' '<<resulti[ii];
+
+                            cout << endl;
+                        }
+*/
+/************** DEBUG DEBUG DEBUG **************/
+
+                        nreq += 2;
+                    } // !chunk->vis_flag[basel][tslot][ch][pol]
+
+                    // Move pointers to the next channel.
+                    for (int scinx = 0; scinx < nrParamsFound; ++scinx)
+                    {
+                        pertReal[scinx]++;
+                        pertImag[scinx]++;
+                    }
+                    realVals++;
+                    imagVals++;
+                }
+            }
+        }
+    }
 
-  LOG_DEBUG_STR("Predict: " << itsPredTimer);
-  LOG_DEBUG_STR("Write: " << itsEqTimer);
-  itsPredTimer.reset();
-  itsEqTimer.reset();
+    //fillEquationTimer.stop();
+    itsEqTimer.stop();
 }
 
+
+/*
 void Prediffer::getData (bool useTree,
              Array<Complex>& dataArr, Array<Bool>& flagArr)
 {
-  int nrusedbl = itsBLInx.size();
+  int nrusedbl = itsBaselineInx.size();
   int nrchan   = itsLastChan-itsFirstChan+1;
   dataArr.resize (IPosition(4, itsNCorr, nrchan, nrusedbl, itsNrTimes));
   flagArr.resize (IPosition(4, itsNCorr, nrchan, nrusedbl, itsNrTimes));
@@ -2025,245 +1357,23 @@ void Prediffer::getData (bool useTree,
   p.first = dataArr.data();
   p.second = flagArr.data();
   if (!useTree) {
-    processData (true, false, false, &Prediffer::getBL, &p);
+    process (true, false, false, &Prediffer::getBaseline, &p);
     return;
   }
   vector<MeqJonesExpr> expr(nrusedbl);
   for (int i=0; i<nrusedbl; ++i) {
-    expr[i] = new MeqJonesMMap (itsMSMapInfo, itsBLInx[i]);
+    expr[i] = new MeqJonesMMap (itsMSMapInfo, itsBaselinenInx[i]);
   }
   pair<pair<Complex*,bool*>*, vector<MeqJonesExpr>*> p1;
   p1.first = &p;
   p1.second = &expr;
-  processData (true, false, false, &Prediffer::getMapBL, &p1);
+  process (true, false, false, &Prediffer::getMapBaseline, &p1);
 }
+*/
 
-void Prediffer::fillEquation (int threadnr, void* arg,
-                  const fcomplex* data, fcomplex*,
-                  const bool* flags,
-                  const MeqRequest& request, int blindex,
-                  bool showd)
-{
-  ///int bl = itsBLInx[blindex];
-  ///int ant1 = itsAnt1[bl];
-  ///int ant2 = itsAnt2[bl];
-  //static NSTimer fillEquationTimer("fillEquation", true);
-  //fillEquationTimer.start();
-  // Get the fitter objects.
-  vector<LSQFit*>& fitters =
-    (*static_cast<vector<vector<LSQFit*> >*>(arg))[threadnr];
-  
-  // Allocate temporary vectors.
-  // If needed, they can be pre-allocated per thread, so there is no
-  // malloc needed for each invocation. Currently it is believed that
-  // the work domains are so large, that the malloc overhead is negligible.
-  // ON the other hand, there are many baselines and the malloc is done
-  // for each of them.
-  uint* indices = &(itsIndexVecs[threadnr][0]);
-  const double** pertReal = &(itsResultVecs[threadnr][0]);
-  const double** pertImag = pertReal + itsNrPert;
-  double* invPert = &(itsDiffVecs[threadnr][0]);
-  double* resultr = invPert + itsNrPert;
-  double* resulti = resultr + itsNrPert;
-  // Get all equations.
-  itsPredTimer.start();
-  MeqJonesExpr& expr = itsExpr[blindex];
-  // Do the actual predict for the entire work domain.
-  MeqJonesResult jresult = expr.getResult (request);
-  itsPredTimer.stop();
-
-  itsEqTimer.start();
-  int nrchan = request.nx();
-  int nrtime = request.ny();
-  int timeSize = itsMSMapInfo.timeSize();
-  // Put the results in a single array for easier handling.
-  const MeqResult* predResults[4];
-  predResults[0] = &(jresult.getResult11());
-  if (itsNCorr == 2) {
-    predResults[1] = &(jresult.getResult22());
-  } else if (itsNCorr == 4) {
-    predResults[1] = &(jresult.getResult12());
-    predResults[2] = &(jresult.getResult21());
-    predResults[3] = &(jresult.getResult22());
-  }
-
-  // Determine start and incr reflecting the order of the observed data.
-  int sdch = itsReverseChan ? itsNCorr * (nrchan - 1) : 0;
-  int inc  = itsReverseChan ? -itsNCorr : itsNCorr;
-  // To avoid having to use large temporary arrays, step through the
-  // data by timestep and correlation.
-  uint nreq=0;
-  
-  for (int corr=0; corr<itsNCorr; corr++, data++, flags++) {
-    if (itsCorr[corr]) {
-      // Get the results for this correlation.
-      const MeqResult& tcres = *predResults[corr];
-      
-      // Get pointers to the main data.
-      const MeqMatrix& val = tcres.getValue();
-      const double* realVals;
-      const double* imagVals;
-      val.dcomplexStorage(realVals, imagVals);
-
-      // Determine which parameters have derivatives and keep that info.
-      // E.g. when solving for station parameters, only a few parameters
-      // per baseline have derivatives.
-      // Note that this is the same for the entire work domain.
-      // Also get pointers to the perturbed values.
-      int nrParamsFound = 0;
-      for (int scinx=0; scinx<itsNrPert; ++scinx) {
-    if (tcres.isDefined(scinx)) {
-      indices[nrParamsFound] = scinx;
-      const MeqMatrix& valp = tcres.getPerturbedValue(scinx);
-      valp.dcomplexStorage (pertReal[nrParamsFound],
-                pertImag[nrParamsFound]);
-      invPert[nrParamsFound] = 1. / tcres.getPerturbation(scinx, 0);
-      nrParamsFound++;
-    }
-      }
-
-      if (nrParamsFound > 0) {
-    const fcomplex* cdata  = data;
-    const bool*     cflags = flags;
-    if (fitters.size() == 1) {
-
-      // No fitter indexing needed if only one fitter.
-      for (int tim=0; tim<nrtime; tim++) {
-        // Loop through all channels.
-        if (showd) {
-          showData (corr, sdch, inc, nrchan, cflags, cdata,
-            realVals, imagVals);
-        }
-        // Form two equations for each unflagged data point.
-        int dch = sdch;
-        for (int ch=0; ch<nrchan; ++ch, dch+=inc) {
-          if (! cflags[dch]) {
-        double diffr = real(cdata[dch]) - *realVals;
-        double diffi = imag(cdata[dch]) - *imagVals;
-        
-#ifdef COMPUTE_SQUARED_ERROR  
-        itsSquaredErrorReal[0] += diffr*diffr;
-        itsSquaredErrorImag[0] += diffi*diffi;
-#endif
-        
-        for (int scinx=0; scinx<nrParamsFound; ++scinx) {
-          // Calculate the derivative for real and imag part.
-          double invp = invPert[scinx];
-          resultr[scinx] = (*pertReal[scinx]++ - *realVals) * invp;
-          resulti[scinx] = (*pertImag[scinx]++ - *imagVals) * invp;
-        }
-        // Now add the equations to the correct fitter object.
-        if (nrParamsFound != itsNrPert) {
-          fitters[0]->makeNorm (nrParamsFound, indices,
-                    resultr, 1., diffr);
-          fitters[0]->makeNorm (nrParamsFound, indices,
-                    resulti, 1., diffi);
-        } else {
-          fitters[0]->makeNorm (resultr, 1., diffr);
-          fitters[0]->makeNorm (resulti, 1., diffi);
-        }
-        if (showd) {
-          cout << "eq"<<corr<<" ch " << 2*ch << " diff " << diffr;
-          for (int ii=0; ii<nrParamsFound; ii++) {
-            cout << ' '<<resultr[ii];
-          }
-          cout << endl;
-          cout << "eq"<<corr<<" ch " << 2*ch+1 << " diff " << diffi;
-          for (int ii=0; ii<nrParamsFound; ii++) {
-            cout << ' '<<resulti[ii];
-          }
-          cout << endl;
-        }
-        nreq += 2;
-          } else {
-        for (int scinx=0; scinx<nrParamsFound; ++scinx) {
-          pertReal[scinx]++;
-          pertImag[scinx]++;
-        }
-          }
-          realVals++;
-          imagVals++;
-        }
-        cdata  += timeSize;       // next observed data time step
-        cflags += nrchan*itsNCorr;
-      }
-    } else {
-      // Multiple fitters, so for each point the correct fitter
-      // has to be determined.
-      for (int tim=0; tim<nrtime; tim++) {
-        // Loop through all channels.
-        if (showd) {
-          showData (corr, sdch, inc, nrchan, cflags, cdata,
-            realVals, imagVals);
-        }
-        // Get first fitter index for this time line.
-        int fitInxT = itsTimeFitInx[tim] * itsFreqNrFit;
-        // Form two equations for each unflagged data point.
-        int dch = sdch;
-        for (int ch=0; ch<nrchan; ++ch, dch+=inc) {
-          if (! cflags[dch]) {
-        int fitInx = fitInxT + itsFreqFitInx[ch];
-        double diffr = real(cdata[dch]) - *realVals;
-        double diffi = imag(cdata[dch]) - *imagVals;
-        
-#ifdef COMPUTE_SQUARED_ERROR  
-        itsSquaredErrorReal[fitInx] += diffr*diffr;
-        itsSquaredErrorImag[fitInx] += diffi*diffi;
-#endif
-        
-        for (int scinx=0; scinx<nrParamsFound; ++scinx) {
-          // Calculate the derivative for real and imag part.
-          double invp = 1. / tcres.getPerturbation(indices[scinx],
-                               fitInx);
-          resultr[scinx] = (*pertReal[scinx]++ - *realVals) * invp;
-          resulti[scinx] = (*pertImag[scinx]++ - *imagVals) * invp;
-        }
-        // Now add the equations to the correct fitter object.
-        if (nrParamsFound != itsNrPert) {
-          fitters[fitInx]->makeNorm (nrParamsFound, indices,
-                         resultr, 1., diffr);
-          fitters[fitInx]->makeNorm (nrParamsFound, indices,
-                         resulti, 1., diffi);
-        } else {
-          fitters[fitInx]->makeNorm (resultr, 1., diffr);
-          fitters[fitInx]->makeNorm (resulti, 1., diffi);
-        }
-        if (showd) {
-          cout << "eq"<<corr<<" ch " << 2*ch << " diff " << diffr;
-          for (int ii=0; ii<nrParamsFound; ii++) {
-            cout << ' '<<resultr[ii];
-          }
-          cout << endl;
-          cout << "eq"<<corr<<" ch " << 2*ch+1 << " diff " << diffi;
-          for (int ii=0; ii<nrParamsFound; ii++) {
-            cout << ' '<<resulti[ii];
-          }
-          cout << endl;
-        }
-        nreq += 2;
-          } else {
-        for (int scinx=0; scinx<nrParamsFound; ++scinx) {
-          pertReal[scinx]++;
-          pertImag[scinx]++;
-        }
-          }
-          realVals++;
-          imagVals++;
-        }
-        cdata  += timeSize;       // next observed data time step
-        cflags += nrchan*itsNCorr;
-      }
-    }
-      }
-    }
-  }
-  //fillEquationTimer.stop();
-  itsEqTimer.stop();
- 
-  ///  cout << "nreq="<<nreq<<endl;
-}
 
-vector<MeqResult> Prediffer::getResults (bool calcDeriv)
+/*
+vector<MeqResult> Prediffer::getResults(bool calcDeriv)
 {
   // Find all nodes to be precalculated.
   setPrecalcNodes (itsExpr);
@@ -2279,7 +1389,7 @@ vector<MeqResult> Prediffer::getResults (bool calcDeriv)
     MeqDomain domain(startFreq, endFreq, time-interv/2, time+interv/2);
     MeqRequest request(domain, nrchan, 1, 0);
     if (calcDeriv) {
-      request = MeqRequest(domain, nrchan, 1, itsNrPert);
+      request = MeqRequest(domain, nrchan, 1, itsContext.derivativeCount);
     }
     // Loop through expressions to be precalculated.
     // We can parallellize them at each level.
@@ -2295,7 +1405,7 @@ vector<MeqResult> Prediffer::getResults (bool calcDeriv)
       }
     }
     // Evaluate for all selected baselines.
-    for (uint blindex=0; blindex<itsBLInx.size(); ++blindex) {
+    for (uint blindex=0; blindex<itsBaselineInx.size(); ++blindex) {
       // Get the result for this baseline.
       MeqJonesExpr& expr = itsExpr[blindex];
       // This is the actual predict.
@@ -2308,12 +1418,12 @@ vector<MeqResult> Prediffer::getResults (bool calcDeriv)
   }
   return results;
 }
+*/
 
-void Prediffer::getBL (int, void* arg,
-               const fcomplex* data, fcomplex*,
-               const bool* flags,
-               const MeqRequest&, int blindex,
-               bool)
+
+/*
+void Prediffer::getBaseline(int, void* arguments, const fcomplex* data,
+    fcomplex*, const bool* flags, const MeqRequest&, int blindex, bool)
 {
   Complex* datap = static_cast<pair<Complex*,bool*>*>(arg)->first;
   bool*    flagp = static_cast<pair<Complex*,bool*>*>(arg)->second;
@@ -2323,12 +1433,11 @@ void Prediffer::getBL (int, void* arg,
   memcpy (flagp+blindex*nrchan*itsNCorr, flags,
       nrchan*itsNCorr*sizeof(bool));
 }
+*/
 
-void Prediffer::getMapBL (int, void* arg,
-              const fcomplex*, fcomplex*,
-              const bool* flags,
-              const MeqRequest& request, int blindex,
-              bool)
+/*
+void Prediffer::getMapBaseline (int, void* arguments, const fcomplex*,
+    fcomplex*, const bool* flags, const MeqRequest& request, int blindex, bool)
 {
   pair<pair<Complex*,bool*>*, vector<MeqJonesExpr>*>* p1 =
     static_cast<pair<pair<Complex*,bool*>*, vector<MeqJonesExpr>*>*>(arg);
@@ -2375,245 +1484,45 @@ void Prediffer::getMapBL (int, void* arg,
     }
   }
 }
+*/
 
-void Prediffer::subtractBL (int, void*,
-                const fcomplex* dataIn, fcomplex* dataOut,
-                const bool*,
-                const MeqRequest& request, int blindex,
-                bool)
-{
-  itsPredTimer.start();
-  MeqJonesExpr& expr = itsExpr[blindex];
-  // Do the actual predict.
-  MeqJonesResult jresult = expr.getResult (request);
-  itsPredTimer.stop();
-
-  itsEqTimer.start();
-  int nrchan = request.nx();
-  int nrtime = request.ny();
-  int timeSize = itsMSMapInfo.timeSize();
-  const double* predReal[4];
-  const double* predImag[4];
-  jresult.getResult11().getValue().dcomplexStorage(predReal[0], predImag[0]);
-  if (itsNCorr == 2) {
-    jresult.getResult22().getValue().dcomplexStorage(predReal[1], predImag[1]);
-  } else if (itsNCorr == 4) {
-    jresult.getResult12().getValue().dcomplexStorage(predReal[1], predImag[1]);
-    jresult.getResult21().getValue().dcomplexStorage(predReal[2], predImag[2]);
-    jresult.getResult22().getValue().dcomplexStorage(predReal[3], predImag[3]);
-  }
-  // Loop through the times and correlations.
-  for (int tim=0; tim<nrtime; tim++) {
-    const fcomplex* idata = dataIn;
-    fcomplex* odata = dataOut;
-    for (int corr=0; corr<itsNCorr; corr++, idata++, odata++) {
-      if (itsCorr[corr]) {
-    const double* realVals = predReal[corr];
-    const double* imagVals = predImag[corr];
-    // Subtract predicted from the data.
-    int dch = itsReverseChan ? itsNCorr * (nrchan - 1) : 0;
-    int inc = itsReverseChan ? -itsNCorr : itsNCorr;
-    if (idata == odata) {
-      for (int ch=0; ch<nrchan; ch++, dch+=inc) {
-        odata[dch] -= makefcomplex(realVals[ch], imagVals[ch]);
-      }
-    } else {
-      for (int ch=0; ch<nrchan; ch++, dch+=inc) {
-        odata[dch] = idata[dch] - makefcomplex(realVals[ch],
-                           imagVals[ch]);
-      }
-    }
-    predReal[corr] += nrchan;
-    predImag[corr] += nrchan;
-      }
-    }
-    dataIn  += timeSize;
-    dataOut += timeSize;
-  }
-  itsEqTimer.stop();
-}
 
-void Prediffer::correctBL (int, void*,
-               const fcomplex*, fcomplex*,
-               const bool*,
-               const MeqRequest& request, int blindex,
-               bool)
-{
-  itsPredTimer.start();
-  MeqJonesResult res = itsCorrExpr[blindex].getResult (request);
-  itsPredTimer.stop();
-  itsEqTimer.start();
-  itsCorrMMap[blindex]->putJResult (res, request);
-  itsEqTimer.stop();
-}
 
-void Prediffer::predictBL (int, void*,
-               const fcomplex*, fcomplex* dataOut,
-               const bool*,
-               const MeqRequest& request, int blindex,
-               bool)
+/*
+void Prediffer::testFlagsBaseline(int, void*, VisData::Pointer chunk,
+    const MeqRequest& request, baseline_t baseline, bool showd)
 {
-  itsPredTimer.start();
-  MeqJonesExpr& expr = itsExpr[blindex];
-  // Do the actual predict.
-  MeqJonesResult jresult = expr.getResult (request);
-  itsPredTimer.stop();
-
-  itsEqTimer.start();
-  int nrchan = request.nx();
-  int nrtime = request.ny();
-  int timeSize = itsMSMapInfo.timeSize();
-  // Put the results in a single array for easier handling.
-  const double* predReal[4];
-  const double* predImag[4];
-  jresult.getResult11().getValue().dcomplexStorage(predReal[0], predImag[0]);
-  if (itsNCorr == 2) {
-    jresult.getResult22().getValue().dcomplexStorage(predReal[1], predImag[1]);
-  } else if (itsNCorr == 4) {
-    jresult.getResult12().getValue().dcomplexStorage(predReal[1], predImag[1]);
-    jresult.getResult21().getValue().dcomplexStorage(predReal[2], predImag[2]);
-    jresult.getResult22().getValue().dcomplexStorage(predReal[3], predImag[3]);
-  }
-  
-  // Loop through the times and correlations.
-  for (int tim=0; tim<nrtime; tim++) {
-    fcomplex* data = dataOut;
-    for (int corr=0; corr<itsNCorr; corr++, data++) {
-      if (itsCorr[corr]) {
-    const double* realVals = predReal[corr];
-    const double* imagVals = predImag[corr];
-    // Store the predict in data.
-    int dch = itsReverseChan ? itsNCorr * (nrchan - 1) : 0;
-    int inc = itsReverseChan ? -itsNCorr : itsNCorr;
-    for (int ch=0; ch<nrchan; ch++, dch+=inc) {
-      data[dch] = makefcomplex(realVals[ch], imagVals[ch]);
-    }
-    predReal[corr] += nrchan;
-    predImag[corr] += nrchan;
-      }
-    }
-    dataOut += timeSize;
-  }
-  itsEqTimer.stop();
-}
+    itsEqTimer.start();
+    int nrchan = request.nx();
+    int nrtime = request.ny();
 
+    map<baseline_t, size_t>::iterator it = chunk->baselines.find(baseline);
+    ASSERT(it != chunk->baselines.end());
+    size_t basel = it->second;
 
-void Prediffer::fillUVW()
-{
-  // Create the UVW nodes.
-  int nrstat = itsStations.size();
-  itsStatUVW.reserve (nrstat);
-  for (int i=0; i<nrstat; ++i) {
-    MeqStatUVW* uvw = 0;
-    // Do it only if the station is actually used.
-    if (itsStations[i] != 0) {
-      // Expression to calculate UVW per station
-      uvw = new MeqStatUVW(itsStations[i], pair<double, double>(itsMSDesc.ra, itsMSDesc.dec), itsMSDesc.arrayPos);
-    }
-    itsStatUVW.push_back (uvw);
-  }
-  if (itsCalcUVW) {
-    return;
-  }
-  // Fill the UVW objects with the uvw-s from the MS.
-  LOG_TRACE_RTTI( "get UVW coordinates from MS" );
-  int nant = itsStatUVW.size();
-  vector<bool> statFnd (nant);
-  vector<bool> statDone (nant);
-  vector<double> statuvw(3*nant);
-
-  // Determine the number of stations (found)
-  statFnd.assign (statFnd.size(), false);
-  int nStatFnd = 0;
-  for (unsigned int bl=0; bl<itsNrBl; bl++) {
-    int a1 = itsMSDesc.ant1[bl];
-    int a2 = itsMSDesc.ant2[bl];
-    if (!statFnd[a1]) {
-      nStatFnd++;
-      statFnd[a1] = true;
-    }
-    if (!statFnd[a2]) {
-      nStatFnd++;
-      statFnd[a2] = true;
-    }
-  }
-  // Map uvw data into memory
-  size_t nrBytes = itsMSDesc.times.size() * itsNrBl * 3 * sizeof(double);
-  double* uvwDataPtr = 0;
-  string UVWFile = getFileForColumn(MS::columnName(MS::UVW));
-  LOG_INFO_STR("Input column " << MS::columnName(MS::UVW) << " maps to: " << UVWFile);
-  MMap* mapPtr = new MMap(UVWFile, MMap::Read);
-  mapPtr->mapFile(0, nrBytes);
-  uvwDataPtr = (double*)mapPtr->getStart();
-
-  // Step time by time through the MS.
-  for (unsigned int tStep=0; tStep < itsMSDesc.times.size(); tStep++) {
-    // Set uvw pointer to beginning of this time
-    unsigned int tOffset = tStep * itsNrBl * 3;
-    double* uvw = uvwDataPtr + tOffset;
-    double time = itsMSDesc.times[tStep];
-
-    // Set UVW of first station used to 0 (UVW coordinates are relative!).
-    statDone.assign (statDone.size(), false);
-    int ant0 = itsMSDesc.ant1[0];
-    statuvw[3*ant0]   = 0;
-    statuvw[3*ant0+1] = 0;
-    statuvw[3*ant0+2] = 0;
-    statDone[ant0] = true;
-    itsStatUVW[ant0]->set (time, 0, 0, 0);
-
-//     cout << "itsStatUVW[" << itsAnt1Data[0] << "] time: " << time << " 0, 0, 0" << endl;
-
-    int ndone = 1;
-    // Loop until all found stations are handled. This is necessary when not all
-    // stations can be calculated in one loop (depends on the order)
-    while (ndone < nStatFnd) {
-      int nd = 0;
-      // Loop over baselines
-      for (unsigned int bl=0; bl<itsNrBl; bl++) {
-    int a1 = itsMSDesc.ant1[bl];
-    int a2 = itsMSDesc.ant2[bl];
-    if (!statDone[a2]) {
-      if (statDone[a1]) {
-        statuvw[3*a2]   = uvw[3*bl]   - statuvw[3*a1];
-        statuvw[3*a2+1] = uvw[3*bl+1] - statuvw[3*a1+1];
-        statuvw[3*a2+2] = uvw[3*bl+2] - statuvw[3*a1+2];
-        statDone[a2] = true;
-        itsStatUVW[a2]->set (time, statuvw[3*a2], statuvw[3*a2+1],
-                 statuvw[3*a2+2]);
-
-//        cout << "itsStatUVW[" << a2 << "] time: " << time << statuvw[3*a2] << " ," << statuvw[3*a2+1] << " ," << statuvw[3*a2+2] << endl;
-
-        ndone++;
-        nd++;
-      }
-    } else if (!statDone[a1]) {
-      if (statDone[a2]) {
-        statuvw[3*a1]   = statuvw[3*a2]   - uvw[3*bl];
-        statuvw[3*a1+1] = statuvw[3*a2+1] - uvw[3*bl+1];
-        statuvw[3*a1+2] = statuvw[3*a2+2] - uvw[3*bl+2];
-        statDone[a1] = true;
-        itsStatUVW[a1]->set (time, statuvw[3*a1], statuvw[3*a1+1],
-                   statuvw[3*a1+2]);
-//        cout << "itsStatUVW[" << a1 << "] time: " << time << statuvw[3*a1] << " ," << statuvw[3*a1+1] << " ," << statuvw[3*a1+2] << endl;
-
-        ndone++;
-        nd++;
-      }
-    }
-    if (ndone == nStatFnd) {
-      break;
-    }
-      } // End loop baselines
-      //      ASSERT (nd > 0);
-    } // End loop stations found
-  } // End loop time
+    // Loop through the times and correlations.
+    for(size_t tslot = 0; tslot < nrtime; ++tslot)
+    {
+        for(set<size_t>::const_iterator it = itsContext.correlations.begin();
+            it != itsContext.correlations.end();
+            ++it)
+        {
+            size_t correlation = *it;
 
-  // Finished with map
-  delete mapPtr;
+            for(size_t ch=0; ch < nrchan; ++ch)
+            {
+                chunk->vis_data[basel][tslot][ch][correlation] =
+                    (chunk->vis_flag[basel][tslot][ch][correlation] ?
+                        makefcomplex(0.0, 0.0) : makefcomplex(1.0, 1.0));
+            }
+       }
+    }
+    itsEqTimer.stop();
 }
+*/
 
-void Prediffer::updateSolvableParms (const vector<double>& values)
+
+void Prediffer::updateSolvableParms(const vector<double>& values)
 {
   // Iterate through all parms.
   for (MeqParmGroup::iterator iter = itsParmGroup.begin();
@@ -2624,13 +1533,12 @@ void Prediffer::updateSolvableParms (const vector<double>& values)
       iter->second.update (values);
     }
   }
-  resetEqLoop();
 }
 
 void Prediffer::updateSolvableParms(size_t solveDomainIndex, const vector<double> unknowns)
 {
     SolveDomainDescriptor &descriptor =
-        itsSolveDomainDescriptors[solveDomainIndex];
+        itsContext.domains[solveDomainIndex];
 
     for(size_t i = 0; i < descriptor.parameters.size(); ++i)
     {
@@ -2639,6 +1547,7 @@ void Prediffer::updateSolvableParms(size_t solveDomainIndex, const vector<double
 }
 
 
+/*
 void Prediffer::updateSolvableParms (const ParmDataInfo& parmDataInfo)
 {
   const vector<ParmData>& parmData = parmDataInfo.parms();
@@ -2661,8 +1570,8 @@ void Prediffer::updateSolvableParms (const ParmDataInfo& parmDataInfo)
       }
     }
   }
-  resetEqLoop();
 }
+*/
 
 void Prediffer::updateSolvableParms()
 {
@@ -2681,26 +1590,16 @@ void Prediffer::updateSolvableParms()
     //       cout.precision (prec);
     }
   }
-  resetEqLoop();
-}
-
-void Prediffer::resetEqLoop()
-{
 }
 
-
 // Log the values of the solvable parameters and the quality indicators of the
 // last iteration to a ParmDB. The type of the parameters is set to 'history'
 // to ensure that they cannot accidentily be used as input for BBSkernel. Also,
 // ParmFacade::getHistory() checks on this type.
-void Prediffer::logIteration(
-    const string &stepName,
-    size_t solveDomainIndex,
-    double rank,
-    double chiSquared,
-    double LMFactor)
+void Prediffer::logIteration(const string &stepName, size_t solveDomainIndex,
+    double rank, double chiSquared, double LMFactor)
 {
-    if(!itsHistoryDB)
+    if(!itsHistoryDBase)
         return;
 
     ostringstream os;
@@ -2713,7 +1612,7 @@ void Prediffer::logIteration(
     vector<int> shape(2, 1);
 
     const SolveDomainDescriptor &descriptor =
-        itsSolveDomainDescriptors[solveDomainIndex];
+        itsContext.domains[solveDomainIndex];
 
     // For each solve domain, log the solver quality indicators and the values of the
     // coefficients of each solvable parameter.
@@ -2729,24 +1628,28 @@ void Prediffer::logIteration(
 
     string stepPrefix = stepName + ":";
     string domainSuffix;
-    if(itsSolveDomains.size() > 1)
+    if(itsContext.domains.size() > 1)
     {
         os.str("");
-        os << ":domain" << setw(((int) log10(double(itsSolveDomains.size())) + 1)) << solveDomainIndex;
+        os << ":domain"
+            << setw(((int) log10(double(itsContext.domains.size())) + 1))
+            << solveDomainIndex;
         domainSuffix = os.str();
     }
 
     value.setNewParm();
     valueRep.setCoeff(&rank, &solvable, shape);
-    itsHistoryDB->putValue(stepPrefix + "solver:rank" + domainSuffix, value);
+    itsHistoryDBase->putValue(stepPrefix + "solver:rank" + domainSuffix, value);
 
     value.setNewParm();
     valueRep.setCoeff(&chiSquared, &solvable, shape);
-    itsHistoryDB->putValue(stepPrefix + "solver:chi_squared" + domainSuffix, value);
+    itsHistoryDBase->putValue(stepPrefix + "solver:chi_squared" + domainSuffix,
+value);
 
     value.setNewParm();
     valueRep.setCoeff(&LMFactor, &solvable, shape);
-    itsHistoryDB->putValue(stepPrefix + "solver:lm_factor" + domainSuffix, value);
+    itsHistoryDBase->putValue(stepPrefix + "solver:lm_factor" + domainSuffix,
+value);
 
     // Log each solvable parameter. Each combinaton of coefficient
     // and solve domain is logged separately. Otherwise, one would
@@ -2771,13 +1674,25 @@ void Prediffer::logIteration(
                 valueRep.setCoeff(&data[j], &solvable, shape);
                 os.str("");
                 os << stepPrefix << descriptor.parameters[i].getName() << ":c" << setw(indexWidth) << j << domainSuffix;
-                itsHistoryDB->putValue(os.str(), value);
+                itsHistoryDBase->putValue(os.str(), value);
             }
         }
     }
 }
 
 
+void Prediffer::writeParms(size_t solveDomainIndex)
+{
+    lock();
+    SolveDomainDescriptor &descriptor = itsContext.domains[solveDomainIndex];
+    for(size_t i = 0; i < descriptor.parameters.size(); ++i)
+    {
+        descriptor.parameters[i].save(solveDomainIndex);
+    }
+    unlock();
+}
+
+
 void Prediffer::writeParms()
 {
 //  BBSTest::ScopedTimer saveTimer("P:write-parm");
@@ -2792,361 +1707,25 @@ void Prediffer::writeParms()
   }
   //  saveTimer.stop();
   //  BBSTest::Logger::log("write-parm", saveTimer);
-  cout << "wrote timeIndex=" << itsTimeIndex
-       << " nrTimes=" << itsNrTimes << endl;
+//  cout << "wrote timeIndex=" << itsTimeIndex
+       //<< " nrTimes=" << itsNrTimes << endl;
 }
 
 #ifdef EXPR_GRAPH
-void Prediffer::writeExpressionGraph(const string &fileName, int baselineIndex)
+void Prediffer::writeExpressionGraph(const string &fileName,
+    baseline_t baseline)
 {
-    ASSERT(baselineIndex >= 0 && baselineIndex < itsExpr.size());
+    MeqJonesExpr& expr = itsExpr[baseline];
+    ASSERTSTR(!expr.isNull(), "Trying to process an unknown baseline.");
 
     ofstream os(fileName.c_str());
     os << "digraph MeasurementEquation" << endl;
     os << "{" << endl;
     os << "node [shape=box];" << endl;
-    itsExpr[baselineIndex].writeExpressionGraph(os);
+    expr.writeExpressionGraph(os);
     os << "}" << endl;
 }
 #endif
 
-void Prediffer::showSettings() const
-{
-  cout << "Prediffer settings:" << endl;
-  cout << "  msname:    " << itsMSName << endl;
-  cout << "  mepname:   " << itsMEPName << endl;
-  cout << "  gsmname:   " << itsGSMMEPName << endl;
-  cout << "  solvparms: " << itsParmData << endl;
-  if (itsReverseChan) {
-    cout << "  stchan:    " << itsNrChan - 1 - itsFirstChan << endl;
-    cout << "  endchan:   " << itsNrChan - 1 - itsLastChan << endl;
-    cout << "    Note: channels are in reversed order" << endl;
-  } else {
-    cout << "  stchan:    " << itsFirstChan << endl;
-    cout << "  endchan:   " << itsLastChan << endl;
-  }
-  cout << "  corr     : " << itsNCorr << "  " << itsCorr[0];
-  for (int i=1; i<itsNCorr; ++i) {
-    cout << ',' << itsCorr[i];
-  }
-  cout << endl;
-  cout << "  calcuvw  : " << itsCalcUVW << endl;
-  cout << endl;
-}
-
-void Prediffer::showData (int corr, int sdch, int inc, int nrchan,
-              const bool* flags, const fcomplex* data,
-              const double* realVals, const double* imagVals)
-{
-  cout << "flag=" << corr << "x ";
-  int dch = sdch;
-  for (int ch=0; ch<nrchan; ch++, dch+=inc) {
-    cout << flags[dch]<< ' ';
-  }
-  cout << endl;
-  cout << "cor=" << corr << "x ";
-  dch = sdch;
-  for (int ch=0; ch<nrchan; ch++, dch+=inc) {
-    cout << '(' << setprecision(12)
-     << real(data[dch])
-     << ',' << setprecision(12)
-     << imag(data[dch])<< ')';
-  }
-  cout << endl;
-  cout << "corr=" << corr << "x ";
-  for (int ch=0; ch<nrchan; ch++) {
-    cout << '(' << setprecision(12)
-     << realVals[ch]
-     << ',' << setprecision(12)
-     << imagVals[ch]<< ')';
-  }
-  cout << endl;
-}
-
-
-// DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED
-// DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED
-
-Prediffer::Prediffer(const string& msName,
-             const LOFAR::ParmDB::ParmDBMeta& meqPdm,
-             const LOFAR::ParmDB::ParmDBMeta& skyPdm,
-             uint ddid,
-             bool calcUVW)
-: itsCalcUVW      (calcUVW),
-  itsMEPName      (meqPdm.getTableName()),
-  itsGSMMEPName   (skyPdm.getTableName()),
-  itsHistoryDB    (0),
-  itsSources      (0),
-  itsNrPert       (0),
-  itsNCorr        (0),
-  itsNrBl         (0),
-  itsTimeIndex    (0),
-  itsNrTimes      (0),
-  itsNrTimesDone  (0),
-  itsInDataMap    (0),
-  itsOutDataMap   (0),
-  itsFlagsMap     (0),
-  itsWeightMap    (0),
-  itsIsWeightSpec (false),
-  itsPredTimer    ("P:predict", false),
-  itsEqTimer      ("P:eq|save", false)
-{
-  // Get absolute path name for MS.
-  itsMSName = Path(msName).absoluteName();
-  LOG_INFO_STR( "Prediffer constructor ("
-        << "'" << itsMSName   << "', "
-        << "'" << meqPdm.getTableName() << "', "
-        << "'" << skyPdm.getTableName() << "', "
-        << itsCalcUVW << ")" );
-  // Read the meta data and map the flags file.
-  //readDescriptiveData(msName);
-  readMeasurementSetMetaData(itsMSName);
-  processMSDesc(ddid);
-    
-  itsGSMMEP = new LOFAR::ParmDB::ParmDB(skyPdm);
-  itsMEP = new LOFAR::ParmDB::ParmDB(meqPdm);
-
-  itsFlagsMap = new FlagsMap(getFileForColumn(MS::columnName(MS::FLAG)), MMap::Read);
-  // Get all sources from the ParmDB.
-  itsSources = new MeqSourceList(*itsGSMMEP, itsParmGroup);
-  // Create the UVW nodes and fill them with uvw-s from MS if not calculated.
-  fillUVW();
-  // Allocate thread private buffers.
-#if defined _OPENMP
-  itsNthread = omp_get_max_threads();
-#else
-  itsNthread = 1;
-#endif
-  itsFlagVecs.resize (itsNthread);
-  itsResultVecs.resize (itsNthread);
-  itsDiffVecs.resize (itsNthread);
-  itsIndexVecs.resize (itsNthread);
-}
-
-bool Prediffer::setStrategyProp (const StrategyProp& strat)
-{
-  itsInDataColumn = strat.getInColumn();
-  // Initially use all correlations.
-  for (int i=0; i<itsNCorr; ++i) {
-    itsCorr[i] = true;
-  }
-  strat.expandPatterns (itsMSDesc.antNames);
-  return selectStations (strat.getAntennas(),         // Available antennas
-             strat.getAutoCorr());
-}
-
-bool Prediffer::setStepProp (const StepProp& stepProp)
-{
-  itsOutDataColumn = stepProp.getOutColumn();
-  stepProp.expandPatterns (itsMSDesc.antNames);
-  if (!selectStep (stepProp.getAnt1(), stepProp.getAnt2(),
-           stepProp.getAutoCorr(),
-           stepProp.getCorr())) {
-    return false;
-  }
-  // If no sources given, use all sources.
-  if (stepProp.getSources().empty()) {
-    makeTree (stepProp.getModel(), itsSources->getSourceNames());
-  } else {
-    makeTree (stepProp.getModel(), stepProp.getSources());
-  }
-  // Put funklets in parms which are not filled yet.
-  for (MeqParmGroup::iterator iter = itsParmGroup.begin();
-       iter != itsParmGroup.end();
-       ++iter)
-  {
-    iter->second.fillFunklets (itsParmValues, itsWorkDomain);
-  }
-  return true;
-}
-
-bool Prediffer::setSolveProp (const SolveProp& solveProp)
-{
-  LOG_INFO_STR( "setSolveProp");
-  const vector<string>& parms = solveProp.getParmPatterns();
-  const vector<string>& excludePatterns = solveProp.getExclPatterns();
-  // Convert patterns to regexes.
-  vector<Regex> parmRegex;
-  for (unsigned int i=0; i<parms.size(); i++) {
-    parmRegex.push_back (Regex::fromPattern(parms[i]));
-  }
-  vector<Regex> excludeRegex;
-  for (unsigned int i=0; i<excludePatterns.size(); i++) {
-    excludeRegex.push_back (Regex::fromPattern(excludePatterns[i]));
-  }
-  // Find all parms matching the parms.
-  // Exclude them if matching an excludePattern
-  int nrsolv = 0;
-  for (MeqParmGroup::iterator iter = itsParmGroup.begin();
-       iter != itsParmGroup.end();
-       ++iter)
-  {
-    String parmName (iter->second.getName());
-    // Loop through all regex-es until a match is found.
-    for (vector<Regex>::iterator incIter = parmRegex.begin();
-     incIter != parmRegex.end();
-     incIter++) {
-      if (parmName.matches(*incIter)) {
-    bool parmExc = false;
-    // Test if not excluded.
-    for (vector<Regex>::const_iterator excIter = excludeRegex.begin();
-         excIter != excludeRegex.end();
-         excIter++) {
-      if (parmName.matches(*excIter)) {
-        parmExc = true;
-        break;
-      }
-    }
-    if (!parmExc) {
-      LOG_TRACE_OBJ_STR( "setSolvable: " << iter->second.getName());
-      iter->second.setSolvable (true);
-      nrsolv++;
-    }
-    break;
-      }
-    }
-  }
-  if (nrsolv == 0) {
-    return false;
-  }
-  initSolvableParms (solveProp.getDomains());
-  return itsNrPert>0;
-}
-
-void Prediffer::readDescriptiveData (const string& fileName)
-{
-  ASSERTSTR(false, "DEPRECATED -- will be removed in next release. Use Prediffer::readMeasurementSetMetaData instead.");
-
-  // Get meta data from description file.
-  string name(fileName+"/vis.des");
-  ifstream istr(name.c_str());
-  ASSERTSTR (istr, "File " << fileName << "/vis.des could not be opened");
-  BlobIBufStream bbs(istr);
-  BlobIStream bis(bbs);
-  bis >> itsMSDesc;
-}
-
-bool Prediffer::selectStations (const vector<int>& antnrs, bool useAutoCorr)
-{
-  int nrant = itsStations.size();
-  // Get all stations actually used.
-  // Default is all stations.
-  if (antnrs.empty()) {
-    itsSelStations = itsStations;
-  } else {
-    // Set given stations.
-    itsSelStations = vector<MeqStation*>(nrant, (MeqStation*)0);
-    for (uint i=0; i<antnrs.size(); i++) {
-      int ant = antnrs[i];
-      if (ant >= 0  &&  ant < nrant) {
-    itsSelStations[ant] = itsStations[ant];
-      }
-    }
-  }
-  // Fill a a matrix telling for each antenna pair where contained in the MS.
-  // First initialize to not contained.
-  itsBLSel.resize (nrant, nrant);
-  itsBLSel = false;
-  // Set if selected for each baseline in the MS.
-  int nr = 0;
-  for (uint i=0; i<itsMSDesc.ant1.size(); ++i) {
-    int a1 = itsMSDesc.ant1[i];
-    int a2 = itsMSDesc.ant2[i];
-    if (itsSelStations[a1] && itsSelStations[a2]) {
-      if (useAutoCorr  ||  a1 != a2) {
-    itsBLSel(a1,a2) = true;
-    nr++;
-      }
-    }
-  }
-  return nr>0;
-}
-
-bool Prediffer::selectStep (const vector<int>& ant1,
-                const vector<int>& ant2,
-                bool useAutoCorrelations,
-                const vector<bool>& corr)
-{
-  int nrant = itsBLSel.nrow();
-  ASSERT (ant1.size() == ant2.size());
-  Matrix<bool> blSel;
-  if (ant1.size() == 0) {
-    // No baselines specified, select all baselines in strategy.
-    blSel = itsBLSel;
-  } else {
-    blSel.resize (nrant, nrant);
-    blSel = false;
-    for (uint i=0; i<ant1.size(); i++) {
-      int a1 = ant1[i];
-      int a2 = ant2[i];
-      if (a1 < nrant  &&  a2 < nrant) {
-    blSel(a1, a2) = itsBLSel(a1, a2);
-      }
-    }
-  }
-  // Unset auto-correlations if needed.
-  if (!useAutoCorrelations) {
-    for (int i=0; i<nrant; i++) {
-      blSel(i,i) = false;
-    }
-  }
-  // Fill the correlations to use. Use all if vector is empty.
-  for (int i=0; i<itsNCorr; ++i) {
-    itsCorr[i] = corr.empty();
-  }
-  if (corr.size() > 0) {
-    // Some values given; first one is always XX (or LL, etc.)
-    itsCorr[0] = corr[0];
-    if (corr.size() > 1  &&  itsNCorr > 1) {
-      if (corr.size() == 2) {
-    // Two values given; last one is always YY (or RR, etc.)
-    itsCorr[itsNCorr-1] = corr[1];
-      } else {
-    // More than 2 must be 4 values.
-    ASSERTSTR (corr.size()==4,
-           "Correlation selection vector must have 1, 2 or 4 flags");
-    if (itsNCorr == 2) {
-      itsCorr[1] = corr[3];
-    } else {
-      itsCorr[1] = corr[1];
-      itsCorr[2] = corr[2];
-      itsCorr[3] = corr[3];
-    }
-      }
-    }
-  }
-  
-  cout << blSel << endl;
-  
-  return fillBaseCorr (blSel);
-}
-
-bool Prediffer::fillBaseCorr (const Matrix<bool>& blSel)
-{
-  // Count the nr of baselines actually used for this step.
-  // Store the seqnr of all selected baselines.
-  itsBLInx.clear();
-  for (uint i=0; i<itsMSDesc.ant1.size(); ++i) {
-    int a1 = itsMSDesc.ant1[i];
-    int a2 = itsMSDesc.ant2[i];
-    if (blSel(a1,a2)) {
-      itsBLInx.push_back (i);
-    }
-  }
-  // Count the nr of selecteed correlations.
-  int nSelCorr = 0;
-  for (int i=0; i<itsNCorr; ++i) {
-    if (itsCorr[i]) {
-      nSelCorr++;
-    }
-  }
-  return (itsBLInx.size() > 0  &&  nSelCorr > 0);
-}
-
-// DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED
-// DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED
-
-
-
 } // namespace BBS
 } // namespace LOFAR
diff --git a/CEP/BB/BBSKernel/src/VisData.cc b/CEP/BB/BBSKernel/src/VisData.cc
new file mode 100644
index 0000000000000000000000000000000000000000..e510e09f52fd4f499ba35ee668c8673a409a6956
--- /dev/null
+++ b/CEP/BB/BBSKernel/src/VisData.cc
@@ -0,0 +1,92 @@
+//# VisData.cc: 
+//#
+//# Copyright (C) 2007
+//# ASTRON (Netherlands Foundation for Research in Astronomy)
+//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//# This program 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 2 of the License, or
+//# (at your option) any later version.
+//#
+//# This program 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 this program; if not, write to the Free Software
+//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//# $Id$
+
+#include <lofar_config.h>
+#include <BBSKernel/VisData.h>
+#include <BBSKernel/Exceptions.h>
+#include <Common/LofarLogger.h>
+
+namespace LOFAR
+{
+namespace BBS 
+{
+
+VisData::VisData(uint32 nTimeslots,
+    uint32 nBaselines,
+    uint32 nChannels,
+    uint32 nPolarizations)
+    :
+    uvw(boost::extents[nBaselines][nTimeslots][3]),
+    tslot_flag(boost::extents[nBaselines][nTimeslots]),
+    vis_flag(boost::extents[nBaselines][nTimeslots][nChannels][nPolarizations]),
+    vis_data(boost::extents[nBaselines][nTimeslots][nChannels][nPolarizations])
+{
+    LOG_DEBUG_STR("Chunk size: "
+        << (nBaselines * nTimeslots * 3 * sizeof(double)
+            + nBaselines * nTimeslots * sizeof(tslot_flag_t)
+            + nBaselines * nTimeslots * nChannels * nPolarizations
+                * sizeof(flag_t)
+            + nBaselines * nTimeslots * nChannels * nPolarizations
+                * sizeof(sample_t))
+            / (1024.0 * 1024.0)
+        << " Mb.");
+}
+
+
+bool VisData::hasBaseline(baseline_t baseline) const
+{
+    map<baseline_t, size_t>::const_iterator it = baselines.find(baseline);
+    return it != baselines.end();
+}
+
+
+size_t VisData::getBaselineIndex(baseline_t baseline) const
+{
+    map<baseline_t, size_t>::const_iterator it = baselines.find(baseline);
+    if(it != baselines.end())
+        return it->second;
+    else
+        THROW(BBSKernelException, "Request for index of unknown baseline "
+            << baseline.first << " - " << baseline.second);
+}
+
+
+bool VisData::hasPolarization(const string &polarization) const
+{
+    map<string, size_t>::const_iterator it = polarizations.find(polarization);
+    return it != polarizations.end();
+}
+
+
+size_t VisData::getPolarizationIndex(const string &polarization) const
+{
+    map<string, size_t>::const_iterator it = polarizations.find(polarization);
+
+    if(it != polarizations.end())
+        return it->second;
+    else
+        THROW(BBSKernelException, "Request for index of unknown polarization "
+            << polarization);
+}
+
+} //# namespace BBS
+} //# namespace LOFAR
diff --git a/CEP/BB/BBSKernel/src/VisSelection.cc b/CEP/BB/BBSKernel/src/VisSelection.cc
new file mode 100644
index 0000000000000000000000000000000000000000..d75de8505cb0524b36c0f88e409ca0272aed79f2
--- /dev/null
+++ b/CEP/BB/BBSKernel/src/VisSelection.cc
@@ -0,0 +1,186 @@
+//# VisSelection.cc: 
+//#
+//# Copyright (C) 2007
+//# ASTRON (Netherlands Foundation for Research in Astronomy)
+//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//# This program 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 2 of the License, or
+//# (at your option) any later version.
+//#
+//# This program 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 this program; if not, write to the Free Software
+//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//# $Id$
+
+#include <lofar_config.h>
+#include <BBSKernel/VisSelection.h>
+
+#include <casa/Quanta/Quantum.h>
+#include <casa/Quanta/MVTime.h>
+
+
+namespace LOFAR
+{
+namespace BBS 
+{
+using casa::Quantum;
+using casa::MVTime;
+using casa::Double;
+
+
+VisSelection::VisSelection()
+{
+    itsFieldFlags.resize(N_FieldEnum, false);
+}
+
+
+void VisSelection::setChannelRange(size_t start, size_t end)
+{
+    if(!isSet(CHANNEL_START)
+        && (!isSet(CHANNEL_END) || start <= itsChannelRange.second))
+    {
+        itsFieldFlags[CHANNEL_START] = true;
+        itsChannelRange.first = start;
+    }
+    else if(start < itsChannelRange.first)
+        itsChannelRange.first = start;
+
+    if(!isSet(CHANNEL_END)
+        && (!isSet(CHANNEL_START) || end >= itsChannelRange.first))
+    {
+        itsFieldFlags[CHANNEL_END] = true;
+        itsChannelRange.second = end;
+    }
+    else if(end > itsChannelRange.second)
+        itsChannelRange.second = end;
+}
+
+
+bool VisSelection::convertTime(const string &in, double &out) const
+{
+    //# TODO: Convert from default epoch to MS epoch (as it may differ from 
+    //# the default!)
+    casa::Quantity time;
+
+    if(in.empty() || !casa::MVTime::read(time, in))
+        return false;
+
+    out = time.getValue("s");
+    return true;
+}
+
+
+void VisSelection::setTimeRange(string start, string end)
+{
+    double time;
+
+    if(convertTime(start, time))
+    {
+        if(!isSet(TIME_START)
+            && (!isSet(TIME_END) || time <= itsTimeRange.second))
+        {
+            itsFieldFlags[TIME_START] = true;
+            itsTimeRange.first = time;
+        }
+        else if(time < itsTimeRange.first)
+            itsTimeRange.first = time;
+    }
+
+    if(convertTime(end, time))
+    {
+        if(!isSet(TIME_END)
+            && (!isSet(TIME_START) || time >= itsTimeRange.first))
+        {
+            itsFieldFlags[TIME_END] = true;
+            itsTimeRange.second = time;
+        }
+        else if(time > itsTimeRange.second)
+            itsTimeRange.second = time;
+    }
+}
+
+
+void VisSelection::setTimeRange(double start, double end)
+{
+    if(!isSet(TIME_START)
+        && (!isSet(TIME_END) || start <= itsTimeRange.second))
+    {
+        itsFieldFlags[TIME_START] = true;
+        itsTimeRange.first = start;
+    }
+    else if(start < itsTimeRange.first)
+        itsTimeRange.first = start;
+
+    if(!isSet(TIME_END)
+        && (!isSet(TIME_START) || end >= itsTimeRange.first))
+    {
+        itsFieldFlags[TIME_END] = true;
+        itsTimeRange.second = end;
+    }
+    else if(end > itsTimeRange.second)
+        itsTimeRange.second = end;
+}
+
+
+void VisSelection::setCorrelations(vector<string> correlations)
+{
+    set<string> selection(correlations.begin(), correlations.end());
+
+    if(!isSet(CORRELATIONS))
+    {
+        itsCorrelations = selection;
+        itsFieldFlags[CORRELATIONS] = true;
+    }
+    else
+    {
+        set<string>::const_iterator it = itsCorrelations.begin();
+        while(it != itsCorrelations.end())
+        {
+            if(selection.count(*it))
+                ++it;
+            else
+                itsCorrelations.erase(it++);
+        }
+    }
+}
+
+
+void VisSelection::setStations(vector<string> stations)
+{
+    set<string> selection(stations.begin(), stations.end());
+
+    if(!isSet(STATIONS))
+    {
+        itsStations = selection;
+        itsFieldFlags[STATIONS] = true;
+    }
+    else
+    {
+        set<string>::const_iterator it = itsStations.begin();
+        while(it != itsStations.end())
+        {
+            if(selection.count(*it))
+                ++it;
+            else
+                itsStations.erase(it++);
+        }
+    }
+}
+
+
+void VisSelection::setBaselineFilter(BaselineFilter filter)
+{
+    itsFieldFlags[BASELINE_FILTER] = true;
+    itsBaselineFilter = filter;
+}
+
+} //# namespace BBS
+} //# namespace LOFAR