diff --git a/.gitattributes b/.gitattributes
index eb7e5409fb7a83c5efb457e379dfbdd4e0771bd6..1248179f7873e9cfa1846b6416dca9e46d2bbfc0 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -226,6 +226,7 @@ CEP/DP3/AOFlagger/include/AOFlagger/msio/system.h -text
 CEP/DP3/AOFlagger/include/AOFlagger/msio/timefrequencydata.h -text
 CEP/DP3/AOFlagger/include/AOFlagger/msio/timefrequencyimager.h -text
 CEP/DP3/AOFlagger/include/AOFlagger/msio/timefrequencymetadata.h -text
+CEP/DP3/AOFlagger/include/AOFlagger/msio/timestepaccessor.h -text
 CEP/DP3/AOFlagger/include/AOFlagger/msio/types.h -text
 CEP/DP3/AOFlagger/include/AOFlagger/ref/concatenatescript.h -text
 CEP/DP3/AOFlagger/include/AOFlagger/ref/copyallscript.h -text
@@ -401,6 +402,7 @@ CEP/DP3/AOFlagger/src/msio/segmentedimage.cpp -text
 CEP/DP3/AOFlagger/src/msio/stokesimager.cpp -text
 CEP/DP3/AOFlagger/src/msio/timefrequencydata.cpp -text
 CEP/DP3/AOFlagger/src/msio/timefrequencyimager.cpp -text
+CEP/DP3/AOFlagger/src/msio/timestepaccessor.cpp -text
 CEP/DP3/AOFlagger/src/ns2bbs.cpp -text
 CEP/DP3/AOFlagger/src/rfi/antennaflagcountplot.cpp -text
 CEP/DP3/AOFlagger/src/rfi/eigenvalue.cpp -text
diff --git a/CEP/DP3/AOFlagger/detectrfi.kdevelop b/CEP/DP3/AOFlagger/detectrfi.kdevelop
index a192725b1bf01e2cdd9af6609ff400fe02aa7b84..768f36ed3d0416d27ee98a8fb8240b772d4b034b 100644
--- a/CEP/DP3/AOFlagger/detectrfi.kdevelop
+++ b/CEP/DP3/AOFlagger/detectrfi.kdevelop
@@ -47,7 +47,7 @@
         <default/>
       </environments>
       <prio>0</prio>
-      <defaulttarget>rfigui</defaulttarget>
+      <defaulttarget>aofrequencyfilter</defaulttarget>
       <makeoptions>-s</makeoptions>
     </make>
     <blacklist/>
diff --git a/CEP/DP3/AOFlagger/include/AOFlagger/msio/timestepaccessor.h b/CEP/DP3/AOFlagger/include/AOFlagger/msio/timestepaccessor.h
new file mode 100644
index 0000000000000000000000000000000000000000..f81c01a9a0f76cdea1db1231dbf258bd1f0b2ae0
--- /dev/null
+++ b/CEP/DP3/AOFlagger/include/AOFlagger/msio/timestepaccessor.h
@@ -0,0 +1,203 @@
+/***************************************************************************
+ *   Copyright (C) 2011 by A.R. Offringa   *
+ *   offringa@astro.rug.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.             *
+ ***************************************************************************/
+
+#ifndef MSIO_TIMESTEP_ACCESSOR_H
+#define MSIO_TIMESTEP_ACCESSOR_H
+
+#include <stdexcept>
+#include <vector>
+
+#include <ms/MeasurementSets/MSTable.h>
+#include <tables/Tables/TableIter.h>
+
+#include <AOFlagger/msio/types.h>
+
+class TimestepAccessorException : public std::runtime_error
+{
+	public: TimestepAccessorException(const std::string &str) : std::runtime_error(str) { }
+};
+
+class TimestepAccessor
+{
+	public:
+		class TimestepIndex
+		{
+			public:
+				TimestepIndex(unsigned tableCount) : tables(new casa::Table*[tableCount]), _tableCount(tableCount)
+				{
+					for(unsigned i=0;i<tableCount;++i)
+						tables[i] = 0;
+				}
+				~TimestepIndex()
+				{
+					FreeTables();
+					delete[] tables;
+				}
+				void FreeTables()
+				{
+					for(unsigned i=0;i<_tableCount;++i)
+					{
+						if(tables[i] != 0)
+						{
+							delete tables[i];
+							tables[i] = 0;
+						}
+					}
+				}
+	
+				casa::Table **tables;
+			private:
+				unsigned _tableCount;
+				TimestepIndex(TimestepIndex &) { }
+				void operator=(TimestepIndex &) { }
+		};
+		struct TimestepData
+		{
+			num_t **realData, **imagData;
+			unsigned antenna1, antenna2;
+			double u,v;
+
+			void Allocate(unsigned polarizationCount, unsigned channelCount)
+			{
+				realData = new num_t*[polarizationCount];
+				imagData = new num_t*[polarizationCount];
+				for(unsigned p=0;p<polarizationCount;++p)
+				{
+					realData[p] = new num_t[channelCount];
+					imagData[p] = new num_t[channelCount];
+				}
+			}
+			void Free(unsigned polarizationCount)
+			{
+				for(unsigned p=0;p<polarizationCount;++p)
+				{
+					delete[] realData[p];
+					delete[] imagData[p];
+				}
+				delete[] realData;
+				delete[] imagData;
+			}
+		};
+
+		TimestepAccessor() : _isOpen(false), _polarizationCount(0), _totalChannelCount(0)
+		{
+		}
+
+		~TimestepAccessor()
+		{
+			if(_isOpen)
+				Close();
+		}
+
+		void Open();
+
+		void Close();
+
+		void AddMS(const std::string &path)
+		{
+			assertNotOpen();
+			SetInfo newInfo;
+			newInfo.path = path;
+			_sets.push_back(newInfo);
+		}
+
+		unsigned TotalChannelCount() const
+		{
+			assertOpen();
+			return _totalChannelCount;
+		}
+
+		unsigned PolarizationCount() const
+		{
+			assertOpen();
+			return _polarizationCount;
+		}
+
+		double LowestFrequency() const
+		{
+			assertOpen();
+			return _lowestFrequency;
+		}
+
+		double HighestFrequency() const
+		{
+			assertOpen();
+			return _highestFrequency;
+		}
+
+		unsigned TableCount() const
+		{
+			return _sets.size();
+		}
+
+		bool ReadNext(TimestepIndex &index, TimestepData &data);
+
+		void Write(TimestepIndex &index, const TimestepData &data);
+
+	private:
+		struct SetInfo
+		{
+			SetInfo() : tableIter(0)
+			{
+			}
+			SetInfo(const SetInfo &source) :
+				path(source.path),
+				tableIter(source.tableIter),
+				bandCount(source.bandCount),
+				channelsPerBand(source.channelsPerBand),
+				highestFrequency(source.highestFrequency),
+				lowestFrequency(source.lowestFrequency)
+			{
+			}
+			void operator=(const SetInfo &source)
+			{
+				path = source.path;
+				tableIter = source.tableIter;
+				bandCount = source.bandCount;
+				channelsPerBand = source.channelsPerBand;
+				highestFrequency = source.highestFrequency;
+				lowestFrequency = source.lowestFrequency;
+			}
+			std::string path;
+			casa::TableIterator *tableIter;
+			unsigned bandCount, channelsPerBand;
+			double highestFrequency, lowestFrequency;
+		};
+
+		typedef std::vector<SetInfo> SetInfoVector;
+
+		bool _isOpen;
+		unsigned _polarizationCount, _totalChannelCount;
+		SetInfoVector _sets;
+		double _highestFrequency, _lowestFrequency;
+
+		void assertOpen() const
+		{
+			if(!_isOpen)
+				throw TimestepAccessorException("Timestep accessor has not been opened yet");
+		}
+		void assertNotOpen() const
+		{
+			if(_isOpen)
+				throw TimestepAccessorException("Timestep accessor has already been opened");
+		}
+};
+
+#endif
diff --git a/CEP/DP3/AOFlagger/include/AOFlagger/ref/concatenatescript.h b/CEP/DP3/AOFlagger/include/AOFlagger/ref/concatenatescript.h
index 441ad196a28576718f3452f9b697941f25260791..41b7846023c671db2d5d1ed04fe238c2bb63eab6 100644
--- a/CEP/DP3/AOFlagger/include/AOFlagger/ref/concatenatescript.h
+++ b/CEP/DP3/AOFlagger/include/AOFlagger/ref/concatenatescript.h
@@ -38,12 +38,12 @@ namespace AOTools
 			stream <<
 				"#!/usr/bin/env python\n\n"
 				"import pyrap.tables as pt\n\n"
-				"pt.concatms([";
+				"pt.msconcat([";
 
 			RefFile::const_iterator i=file.begin();
 			if(i!=file.end())
 			{
-				stream << '\"' << i->Path() << '\"';
+				stream << "\"/net/" << i->Node() << i->Path() << '\"';
 				++i;
 			}
 
diff --git a/CEP/DP3/AOFlagger/src/CMakeLists.txt b/CEP/DP3/AOFlagger/src/CMakeLists.txt
index 73104a9edd48f1024e6cb8164ffc8cc8759c144d..f95292b391116c9829bb77cfd3d6e796174f759b 100644
--- a/CEP/DP3/AOFlagger/src/CMakeLists.txt
+++ b/CEP/DP3/AOFlagger/src/CMakeLists.txt
@@ -4,7 +4,7 @@ include(LofarPackageVersion)
 
 lofar_add_bin_program(rfihistory rfihistory.cpp)
 
-lofar_add_bin_program(aofrequencyfilter aofrequencyfilter.cpp rfi/thresholdtools.cpp util/rng.cpp msio/image2d.cpp msio/fitsfile.cpp util/aologger.cpp)
+lofar_add_bin_program(aofrequencyfilter aofrequencyfilter.cpp rfi/thresholdtools.cpp util/rng.cpp msio/image2d.cpp msio/fitsfile.cpp msio/timestepaccessor.cpp util/aologger.cpp)
 
 lofar_add_bin_program(aorefscript aorefscript.cpp)
 
diff --git a/CEP/DP3/AOFlagger/src/aofrequencyfilter.cpp b/CEP/DP3/AOFlagger/src/aofrequencyfilter.cpp
index 253b15919b4cc820a22b2fa30a7ef97e65e0afd8..5b370e4998132771be1d467d2855ac059699fd54 100644
--- a/CEP/DP3/AOFlagger/src/aofrequencyfilter.cpp
+++ b/CEP/DP3/AOFlagger/src/aofrequencyfilter.cpp
@@ -14,7 +14,9 @@
 
 #include <AOFlagger/rfi/thresholdtools.h>
 #include <AOFlagger/imaging/uvimager.h>
+
 #include <AOFlagger/msio/system.h>
+#include <AOFlagger/msio/timestepaccessor.h>
 
 using namespace std;
 
@@ -30,90 +32,50 @@ double uvDist(double u, double v, double firstFrequency, double lastFrequency)
 	return sqrt(ud * ud + vd * vd) / UVImager::SpeedOfLight();
 }
 
-// This represents data that is constant for all threads
-struct SetInfo
-{
-	unsigned bandCount;
-	unsigned frequencyCount;
-	unsigned polarizationCount;
-};
-
 // This represents the data that is specific for a single thread
 struct TaskInfo
 {
-	TaskInfo() : length(0), convolutionSize(0.0), table(0), dataColumn(0), realData(0), imagData(0) { }
+	TaskInfo() : length(0), convolutionSize(0.0), index(0), data() { }
 	TaskInfo(const TaskInfo &source) :
 	 length(source.length),
 	 convolutionSize(source.convolutionSize),
-	 table(source.table),
-	 dataColumn(source.dataColumn),
-	 realData(source.realData),
-	 imagData(source.imagData)
+	 index(source.index),
+	 data(source.data)
 	{
 	}
 	void operator=(const TaskInfo &source)
 	{
 		length = source.length;
 		convolutionSize = source.convolutionSize;
-		table = source.table;
-		dataColumn = source.dataColumn;
-		realData = source.realData;
-		imagData = source.imagData;
+		index = source.index;
+		data = source.data;
 	}
 	
 	unsigned length;
 	double convolutionSize;
-	casa::Table *table;
-	casa::ArrayColumn<casa::Complex> *dataColumn;
-	float
-		**realData,
-		**imagData;
+	TimestepAccessor::TimestepIndex *index;
+	TimestepAccessor::TimestepData data;
 };
 
-void performAndWriteConvolution(const SetInfo &set, TaskInfo task, boost::mutex &mutex)
+void performAndWriteConvolution(TimestepAccessor &accessor, TaskInfo task, boost::mutex &mutex)
 {
+	unsigned polarizationCount = accessor.PolarizationCount();
 	if(task.convolutionSize > 1.0)
 	{
 		// Convolve the data
-		for(unsigned p=0;p<set.polarizationCount;++p)
+		for(unsigned p=0;p<polarizationCount;++p)
 		{
-			ThresholdTools::OneDimensionalSincConvolution(task.realData[p], task.length, task.convolutionSize);
-			ThresholdTools::OneDimensionalSincConvolution(task.imagData[p], task.length, task.convolutionSize);
+			ThresholdTools::OneDimensionalSincConvolution(task.data.realData[p], task.length, task.convolutionSize);
+			ThresholdTools::OneDimensionalSincConvolution(task.data.imagData[p], task.length, task.convolutionSize);
 		}
 
-		boost::mutex::scoped_lock lock(mutex);
 		// Copy data back to tables
-		for(unsigned i=0;i<set.bandCount;++i)
-		{
-			casa::Array<casa::Complex> dataArray = (*task.dataColumn)(i);
-			casa::Array<casa::Complex>::iterator dataIterator = dataArray.begin();
-			unsigned index = i * set.frequencyCount;
-			for(unsigned f=0;f<set.frequencyCount;++f)
-			{
-				for(unsigned p=0;p<set.polarizationCount;++p)
-				{
-					*dataIterator = casa::Complex(task.realData[p][index], task.imagData[p][index]);
-					++dataIterator;
-				}
-				++index;
-			}
-			task.dataColumn->basePut(i, dataArray);
-		}
+		boost::mutex::scoped_lock lock(mutex);
+		accessor.Write(*task.index, task.data);
 		lock.unlock();
 	}
 
-	// Free memory
-	boost::mutex::scoped_lock lock(mutex);
-	for(unsigned p=0;p<set.polarizationCount;++p)
-	{
-		delete[] task.realData[p];
-		delete[] task.imagData[p];
-	}
-	delete[] task.realData;
-	delete[] task.imagData;
-	
-	delete task.dataColumn;
-	delete task.table;
+	task.data.Free(polarizationCount);
 }
 
 struct ThreadFunction
@@ -126,8 +88,8 @@ struct ThreadFunction
 class ThreadControl
 {
 	public:
-		ThreadControl(unsigned threadCount, const struct SetInfo &setInfo)
-			: _setInfo(setInfo), _threadCount(threadCount), _isFinishing(false)
+		ThreadControl(unsigned threadCount, TimestepAccessor &accessor)
+			: _accessor(accessor), _threadCount(threadCount), _isFinishing(false)
 		{
 			for(unsigned i=0;i<threadCount;++i)
 			{
@@ -173,10 +135,10 @@ class ThreadControl
 			_dataAvailableCondition.notify_all();
 			_threadGroup.join_all();
 		}
-		const struct SetInfo &SetInfo() const { return _setInfo; }
 		boost::mutex &WriteMutex() { return _writeMutex; }
+		TimestepAccessor &Accessor() { return _accessor; }
 	private:
-		const struct SetInfo _setInfo;
+		TimestepAccessor &_accessor;
 		boost::thread_group _threadGroup;
 		unsigned _threadCount;
 		bool _isFinishing;
@@ -194,7 +156,7 @@ void ThreadFunction::operator()()
 	bool hasTask = threadControl->WaitForTask(task);
 	while(hasTask)
 	{
-		performAndWriteConvolution(threadControl->SetInfo(), task, threadControl->WriteMutex());
+		performAndWriteConvolution(threadControl->Accessor(), task, threadControl->WriteMutex());
 		hasTask = threadControl->WaitForTask(task);
 	}
 	cout << "Thread " << number << " finished\n";
@@ -202,169 +164,81 @@ void ThreadFunction::operator()()
 
 int main(int argc, char *argv[])
 {
-	if(argc != 3)
+	if(argc < 3)
 	{
-		cerr << "Syntax: " << argv[0] << " <fringe size> <MS>\n";
+		cerr << "Syntax: " << argv[0] << " <fringe size> <MS1> [<MS2> [..]]\n";
 		cerr << " fringe size is a double and should be given in units of wavelength / fringe.\n";
 	} else {
 		const double fringeSize = atof(argv[1]);
-		const string msFilename = argv[2];
 		cout << "Fringe size: " << fringeSize << '\n';
 
-		casa::MeasurementSet ms(msFilename);
-		casa::Table mainTable(msFilename, casa::Table::Update);
-		class SetInfo setInfo;
-
-		//count number of polarizations
-		casa::Table polTable = ms.polarization();
-		casa::ROArrayColumn<int> corTypeColumn(polTable, "CORR_TYPE"); 
-		setInfo.polarizationCount = corTypeColumn(0).shape()[0];
-		cout << "Number of polarizations: " << setInfo.polarizationCount << '\n';
+		TimestepAccessor accessor;
+		for(int i=2;i<argc;++i)
+			accessor.AddMS(argv[i]);
+		accessor.Open();
 
-		// Find lowest and highest frequency and check order
-		double lowestFrequency = 0.0, highestFrequency = 0.0;
-		casa::Table spectralWindowTable = ms.spectralWindow();
-		casa::ROArrayColumn<double> frequencyCol(spectralWindowTable, "CHAN_FREQ");
-		for(unsigned b=0;b<spectralWindowTable.nrow();++b)
-		{
-			casa::Array<double> frequencyArray = frequencyCol(b);
-			casa::Array<double>::const_iterator frequencyIterator = frequencyArray.begin();
-			while(frequencyIterator != frequencyArray.end())
-			{
-				double frequency = *frequencyIterator;
-				if(lowestFrequency == 0.0) lowestFrequency = frequency;
-				if(frequency < lowestFrequency || frequency <= highestFrequency)
-				{
-					cerr << "ERROR: Channels are not ordered in increasing frequency!\n";
-					abort();
-				}
-				highestFrequency = frequency;
-				++frequencyIterator;
-			}
-		}
-		setInfo.bandCount = spectralWindowTable.nrow();
+		cout << "Number of polarizations: " << accessor.PolarizationCount() << '\n';
 		cout
-			<< "Number of bands: " << setInfo.bandCount
-			<< " (" << round(lowestFrequency/1e6) << " MHz - "
-			<< round(highestFrequency/1e6) << " MHz)\n";
+			<< "Number of channels: " << accessor.TotalChannelCount()
+			<< " (" << round(accessor.LowestFrequency()/1e6) << " MHz - "
+			<< round(accessor.HighestFrequency()/1e6) << " MHz)\n";
 
-		setInfo.frequencyCount =
-			casa::ROArrayColumn<casa::Complex>(mainTable, "DATA")(0).shape()[1];
-		cout << "Channels per band: " << setInfo.frequencyCount << '\n';
-
-		const unsigned long totalIterations =
-			mainTable.nrow() / spectralWindowTable.nrow();
+		const unsigned long totalIterations = 1; // TODO
 		cout << "Total iterations: " << totalIterations << '\n';
 		
-		unsigned processorCount = System::ProcessorCount();
+		const unsigned processorCount = System::ProcessorCount();
 		cout << "CPUs: " << processorCount << '\n';
-		ThreadControl threads(processorCount, setInfo);
+		ThreadControl threads(processorCount, accessor);
 
-		// Create the sorted table and iterate over it
-		casa::Block<casa::String> names(4);
-		names[0] = "TIME";
-		names[1] = "ANTENNA1";
-		names[2] = "ANTENNA2";
-		names[3] = "DATA_DESC_ID";
-		cout << "Sorting...\n";
-		casa::Table sortab = mainTable.sort(names);
-		cout << "Iterating...\n";
-		unsigned long iterSteps = 0;
-		names.resize(3, true, true);
-		casa::TableIterator iter (sortab, names, casa::TableIterator::Ascending, casa::TableIterator::NoSort);
 		double maxFringeChannels = 0.0, minFringeChannels = 1e100;
-		while (! iter.pastEnd()) {
+		const unsigned totalChannels = accessor.TotalChannelCount();
+
+		TimestepAccessor::TimestepIndex *index = new TimestepAccessor::TimestepIndex(accessor.TableCount());
+		TimestepAccessor::TimestepData data;
+
+		data.Allocate(accessor.PolarizationCount(), totalChannels);
+		
+		unsigned iterSteps = 0;
+
+		boost::mutex::scoped_lock lock(threads.WriteMutex());
+		while(accessor.ReadNext(*index, data)) {
+			lock.unlock();
+
 			TaskInfo task;
-			task.table = new casa::Table(iter.table());
-			
-			int antenna1, antenna2;
-			// we start a new block to let the columns go out of scope (table might be freed
-			// before end of parent block)
-			{
-				casa::ROScalarColumn<int> antenna1Column =
-						casa::ROScalarColumn<int>(*task.table, "ANTENNA1");
-				casa::ROScalarColumn<int> antenna2Column =
-						casa::ROScalarColumn<int>(*task.table, "ANTENNA2");
-				antenna1 = antenna1Column(0);
-				antenna2 = antenna2Column(0);
-			}
+			task.index = index;
+			task.data = data;
 			
 			// Skip autocorrelations
-			if(antenna1 == antenna2)
+			if(data.antenna1 == data.antenna2)
 			{
-				delete task.table;
+				data.Free(accessor.PolarizationCount());
+				delete index;
 			} else
 			{
-				task.dataColumn = new casa::ArrayColumn<casa::Complex>(*task.table, "DATA");
-
-				// Check number of channels & bands
-				const casa::IPosition &dataShape = task.dataColumn->shape(0);
-				if(dataShape[1] != setInfo.frequencyCount) {
-					std::cerr << "ERROR: bands do not have equal number of channels!\n";
-					abort();
-				}
-				if(task.table->nrow() != setInfo.bandCount) {
-					std::cerr << "ERROR: inconsistent band information in specific correlation/time step\n"
-						" (rows in table iterator's table: " << task.table->nrow() <<
-						", in set: " << setInfo.bandCount << ")\n";
-					abort();
-				}
-	
-				// Retrieve uv info and calculate the convolution size
-				double u, v;
-				{
-					casa::ROArrayColumn<double> uvwColumn =
-						casa::ROArrayColumn<double>(*task.table, "UVW");
-					casa::Array<double> uvwArray = uvwColumn(0);
-					casa::Array<double>::const_iterator uvwIterator = uvwArray.begin();
-					u = *uvwIterator;
-					++uvwIterator;
-					v = *uvwIterator;
-				}
-				task.length = setInfo.bandCount * setInfo.frequencyCount;
-				task.convolutionSize = fringeSize * (double) task.length / uvDist(u, v, lowestFrequency, highestFrequency);
+				// Calculate the convolution size
+				double u = data.u, v = data.v;
+				task.length = totalChannels;
+				task.convolutionSize = fringeSize * (double) totalChannels / uvDist(u, v, accessor.LowestFrequency(), accessor.HighestFrequency());
 				if(task.convolutionSize > maxFringeChannels) maxFringeChannels = task.convolutionSize;
 				if(task.convolutionSize < minFringeChannels) minFringeChannels = task.convolutionSize;
+				task.data = data;
 
-				// Allocate memory for putting the data of all channels in an array, for each polarization
-				task.realData = new float*[setInfo.polarizationCount];
-				task.imagData = new float*[setInfo.polarizationCount];
-				for(unsigned p=0;p<setInfo.polarizationCount;++p)
-				{
-					task.realData[p] = new float[task.length];
-					task.imagData[p] = new float[task.length];
-				}
-				
-				boost::mutex::scoped_lock lock(threads.WriteMutex());
-				// Copy data from tables in arrays
-				for(unsigned i=0;i<setInfo.bandCount;++i)
-				{
-					casa::Array<casa::Complex> dataArray = (*task.dataColumn)(i);
-					casa::Array<casa::Complex>::const_iterator dataIterator = dataArray.begin();
-					unsigned index = i * setInfo.frequencyCount;
-					for(unsigned f=0;f<setInfo.frequencyCount;++f)
-					{
-						for(unsigned p=0;p<setInfo.polarizationCount;++p)
-						{
-							task.realData[p][index] = (*dataIterator).real();
-							task.imagData[p][index] = (*dataIterator).imag();
-							++dataIterator;
-						}
-						++index;
-					}
-				}
-				lock.unlock();
-
+				// Add task
 				threads.PushTask(task);
 			}
 
-			iter.next();
+			index = new TimestepAccessor::TimestepIndex(accessor.TableCount());
+			data.Allocate(accessor.PolarizationCount(), totalChannels);
+
+			lock.lock();
 			++iterSteps;
-			if((iterSteps * 100UL) % totalIterations < 100UL)
-				cout << '.' << flush;
-			if((iterSteps * 10UL) % totalIterations < 10UL)
-				cout << (iterSteps*100/totalIterations) << '%' << flush;
+
+			if(iterSteps%100==0) cout << '.' << flush;
 		}
+		lock.unlock();
+
+		data.Free(accessor.PolarizationCount());
+
 		cout << '\n';
 		threads.Finish();
 		cout
diff --git a/CEP/DP3/AOFlagger/src/msio/timestepaccessor.cpp b/CEP/DP3/AOFlagger/src/msio/timestepaccessor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bceb4f370eba9fd880205a8924f1bc968e5898ba
--- /dev/null
+++ b/CEP/DP3/AOFlagger/src/msio/timestepaccessor.cpp
@@ -0,0 +1,177 @@
+#include <AOFlagger/msio/timestepaccessor.h>
+
+#include <ms/MeasurementSets/MeasurementSet.h>
+#include <ms/MeasurementSets/MSColumns.h>
+
+void TimestepAccessor::Open()
+{
+	assertNotOpen();
+
+	_totalChannelCount = 0;
+	_highestFrequency = 0.0;
+	_lowestFrequency = 0.0;
+
+	for(SetInfoVector::iterator i=_sets.begin(); i!=_sets.end(); ++i)
+	{
+		SetInfo &set = *i;
+
+		casa::MeasurementSet ms(set.path);
+		casa::Table mainTable(set.path, casa::Table::Update);
+
+		// Create the sorted table and iterator
+		casa::Block<casa::String> names(4);
+		names[0] = "TIME";
+		names[1] = "ANTENNA1";
+		names[2] = "ANTENNA2";
+		names[3] = "DATA_DESC_ID";
+		casa::Table sortab = mainTable.sort(names);
+		names.resize(3, true, true);
+		set.tableIter = new casa::TableIterator(sortab, names, casa::TableIterator::Ascending, casa::TableIterator::NoSort);
+
+		// Check number of polarizations
+		casa::Table polTable = ms.polarization();
+		casa::ROArrayColumn<int> corTypeColumn(polTable, "CORR_TYPE");
+		if(_polarizationCount==0 && i==_sets.begin())
+			_polarizationCount = corTypeColumn(0).shape()[0];
+		else if(_polarizationCount != corTypeColumn(0).shape()[0])
+			throw TimestepAccessorException("Number of polarizations don't match!");
+
+		// Find lowest and highest frequency and check order
+		set.lowestFrequency = 0.0;
+		set.highestFrequency = 0.0;
+		casa::Table spectralWindowTable = ms.spectralWindow();
+		casa::ROArrayColumn<double> frequencyCol(spectralWindowTable, "CHAN_FREQ");
+		for(unsigned b=0;b<spectralWindowTable.nrow();++b)
+		{
+			casa::Array<double> frequencyArray = frequencyCol(b);
+			casa::Array<double>::const_iterator frequencyIterator = frequencyArray.begin();
+			while(frequencyIterator != frequencyArray.end())
+			{
+				double frequency = *frequencyIterator;
+				if(set.lowestFrequency == 0.0) set.lowestFrequency = frequency;
+				if(frequency < set.lowestFrequency || frequency <= set.highestFrequency)
+					throw TimestepAccessorException("Channels or bands are not ordered in increasing frequency");
+				set.highestFrequency = frequency;
+				++frequencyIterator;
+			}
+		}
+		if(set.lowestFrequency < _highestFrequency)
+			throw TimestepAccessorException("Sub-bands are not given in order of increasing frequency");
+		if(_lowestFrequency == 0.0) _lowestFrequency = set.lowestFrequency;
+		_highestFrequency = set.highestFrequency;
+
+		set.bandCount = spectralWindowTable.nrow();
+		set.channelsPerBand = casa::ROArrayColumn<casa::Complex>(mainTable, "DATA")(0).shape()[1];
+		_totalChannelCount += set.bandCount * set.channelsPerBand;
+	}
+	_isOpen = true;
+}
+
+void TimestepAccessor::Close()
+{
+	assertOpen();
+
+	for(SetInfoVector::iterator i=_sets.begin(); i!=_sets.end(); ++i)
+	{
+		delete i->tableIter;
+	}
+	_isOpen = false;
+}
+
+bool TimestepAccessor::ReadNext(TimestepAccessor::TimestepIndex &index, TimestepAccessor::TimestepData &data)
+{
+	assertOpen();
+
+	index.FreeTables();
+
+	double timeStep = 0.0;
+	unsigned valIndex = 0;
+	casa::Table **tablePtr = index.tables;
+
+	for(SetInfoVector::iterator i=_sets.begin(); i!=_sets.end(); ++i)
+	{
+		SetInfo &set = *i;
+
+		if(set.tableIter->pastEnd())
+			return false;
+		casa::Table table(set.tableIter->table());
+		*tablePtr = new casa::Table(table);
+
+		// Check timestep & read u,v coordinates & antenna's
+		casa::ROScalarColumn<double> timeColumn = casa::ROScalarColumn<double>(table, "TIME");
+		casa::ROArrayColumn<double> uvwColumn = casa::ROArrayColumn<double>(table, "UVW");
+		if(timeStep == 0.0) {
+			timeStep = timeColumn(0);
+			casa::Array<double> uvwArray = uvwColumn(0);
+			casa::Array<double>::const_iterator uvwIterator = uvwArray.begin();
+			data.u = *uvwIterator;
+			++uvwIterator;
+			data.v = *uvwIterator;
+			casa::ROScalarColumn<int>
+				antenna1Column = casa::ROScalarColumn<int>(table, "ANTENNA1"),
+				antenna2Column = casa::ROScalarColumn<int>(table, "ANTENNA2");
+			data.antenna1 = antenna1Column(0);
+			data.antenna2 = antenna2Column(0);
+		}
+		else if(timeStep != timeColumn(0))
+			throw TimestepAccessorException("Sets do not have same time steps");
+
+		// Copy data from tables in arrays
+		casa::ROArrayColumn<casa::Complex> dataColumn(table, "DATA");
+		for(unsigned band=0;band<set.bandCount;++band)
+		{
+			casa::Array<casa::Complex> dataArray = dataColumn(band);
+			casa::Array<casa::Complex>::const_iterator dataIterator = dataArray.begin();
+			for(unsigned f=0;f<set.channelsPerBand;++f)
+			{
+				for(unsigned p=0;p<_polarizationCount;++p)
+				{
+					data.realData[p][valIndex] = (*dataIterator).real();
+					data.imagData[p][valIndex] = (*dataIterator).imag();
+					++dataIterator;
+				}
+				++valIndex;
+			}
+		}
+
+		set.tableIter->next();
+		++tablePtr;
+	}
+	return true;
+}
+
+void TimestepAccessor::Write(TimestepAccessor::TimestepIndex &index, const TimestepAccessor::TimestepData &data)
+{
+	assertOpen();
+
+	casa::Table **tablePtr = index.tables;
+	unsigned valIndex = 0;
+
+	for(SetInfoVector::iterator i=_sets.begin(); i!=_sets.end(); ++i)
+	{
+		const SetInfo &set = *i;
+
+		casa::Table &table = **tablePtr;
+
+		// Copy data from arrays in tables
+		casa::ArrayColumn<casa::Complex> dataColumn(table, "DATA");
+		for(unsigned band=0;band<set.bandCount;++band)
+		{
+			casa::Array<casa::Complex> dataArray = dataColumn(band);
+			casa::Array<casa::Complex>::iterator dataIterator = dataArray.begin();
+			for(unsigned f=0;f<set.channelsPerBand;++f)
+			{
+				for(unsigned p=0;p<_polarizationCount;++p)
+				{
+					(*dataIterator).real() = data.realData[p][valIndex];
+					(*dataIterator).imag() = data.imagData[p][valIndex];
+					++dataIterator;
+				}
+				++valIndex;
+			}
+			dataColumn.basePut(band, dataArray);
+		}
+		set.tableIter->next();
+	}
+	index.FreeTables();
+}