--- a/Utilities/funkyDoCalc/funkyDoCalc.C
+++ b/Utilities/funkyDoCalc/funkyDoCalc.C
@@ -51,12 +51,60 @@
 
 #include "AccumulationCalculation.H"
 
+template <typename Type>
+Ostream& writeValue(
+    Ostream &o,
+    Type value
+) {
+    for(direction i=0;i<pTraits<Type>::nComponents;i++) {
+        o << ","
+            << component(value,i);
+    }
+    return o;
+}
+
+// Yeah. Global. Bad. But convenient
+fileName dataDir="";
+
+typedef HashPtrTable<OFstream> CsvFiles;
+CsvFiles csvFiles;
+
 template <class T>
 void writeData(
     CommonValueExpressionDriver &driver,
-    const List<NumericAccumulationNamedEnum::accuSpecification> &accumulations
+    const List<NumericAccumulationNamedEnum::accuSpecification> &accumulations,
+    const Time &time,
+    const word &name,
+    const bool writeCsv,
+    const bool writeDistributions
 )
 {
+    if(
+        ( writeCsv || writeDistributions)
+        &&
+        !exists(dataDir)
+    ) {
+        //        Info << "Creating data directory " << dataDir << endl;
+        mkDir(dataDir);
+    }
+
+    bool firstTime=false;
+    OStringStream header;
+    OStringStream data;
+
+    if(writeCsv) {
+        if(!csvFiles.found(name)) {
+            firstTime=true;
+            csvFiles.insert(
+                name,
+                new OFstream(dataDir / name+".csv")
+            );
+        }
+    }
+
+    header << "Time";
+    data << time.timeName();
+
     bool isPoint=driver.result().isPoint();
 
     Field<T> result=driver.getResult<T>(isPoint);
@@ -72,7 +120,44 @@
 
         T val=calculator(accu);
 
+        if(pTraits<T>::nComponents==1) {
+            header << "," << accumulations[i];
+        } else {
+            for(label j=0;j<pTraits<T>::nComponents;j++) {
+                header << "," << accumulations[i] << "_"
+                    << pTraits<T>::componentNames[j];
+            }
+        }
+        writeValue(data,val);
+
         Info << " " << accu << "=" << val;
+    }
+
+    if(writeDistributions) {
+        Info << " - write distribution";
+
+        fileName toDir=dataDir
+            /
+            time.timeName();
+
+        mkDir(toDir);
+
+        calculator.distribution().write(
+            toDir
+            /
+            name
+        );
+        calculator.weightedDistribution().write(
+            toDir
+            /
+            name+"_weighted"
+        );
+    }
+    if(writeCsv) {
+        if(firstTime) {
+            *csvFiles[name] << header.str().c_str() << endl;
+        }
+        *csvFiles[name] << data.str().c_str() << endl;
     }
 }
 
@@ -88,6 +173,9 @@
     argList::validOptions.insert("noDimensionChecking","");
     argList::validOptions.insert("foreignMeshesThatFollowTime",
                                   "<list of mesh names>");
+    argList::validOptions.insert("writeCsv","");
+    argList::validOptions.insert("writeDistributions","");
+    argList::validOptions.insert("noDimensionChecking","");
 
 #   include "setRootCase.H"
 
@@ -96,6 +184,11 @@
     IFstream theFile(args.args()[1]);
     dictionary theExpressions(theFile);
     wordList foreignMeshesThatFollowTime(0);
+
+    bool globalWriteCsv=args.options().found("writeCsv");
+    bool globalWriteDistributions=args.options().found("writeDistributions");
+
+    dataDir=args.path()/fileName(args.args()[1]).name()+"_data";
 
     if (!args.options().found("time") && !args.options().found("latestTime")) {
         FatalErrorIn("main()")
@@ -157,9 +250,20 @@
 
         forAllConstIter(IDLList<entry>, theExpressions, iter)
         {
-            Info << iter().keyword() << " : " << flush;
+            const word name=iter().keyword();
+
+           Info << name << " : " << flush;
 
             const dictionary &dict=iter().dict();
+
+            bool writeCsv=
+                globalWriteCsv
+                ||
+                dict.lookupOrDefault<bool>("writeCsv",false);
+            bool writeDistributions=
+                globalWriteDistributions
+                ||
+                dict.lookupOrDefault<bool>("writeDistributions",false);
 
             autoPtr<CommonValueExpressionDriver> driver=
                 CommonValueExpressionDriver::New(dict,mesh);
@@ -182,15 +286,20 @@
             word rType=driver->CommonValueExpressionDriver::getResultType();
 
             if(rType==pTraits<scalar>::typeName) {
-                writeData<scalar>(driver(),accumulations);
+                writeData<scalar>(driver(),accumulations,runTime,
+                                  name,writeCsv,writeDistributions);
             } else if(rType==pTraits<vector>::typeName) {
-                writeData<vector>(driver(),accumulations);
+                writeData<vector>(driver(),accumulations,runTime,
+                                  name,writeCsv,writeDistributions);
             } else if(rType==pTraits<tensor>::typeName) {
-                writeData<tensor>(driver(),accumulations);
+                writeData<tensor>(driver(),accumulations,runTime,
+                                  name,writeCsv,writeDistributions);
             } else if(rType==pTraits<symmTensor>::typeName) {
-                writeData<symmTensor>(driver(),accumulations);
+                writeData<symmTensor>(driver(),accumulations,runTime,
+                                  name,writeCsv,writeDistributions);
             } else if(rType==pTraits<sphericalTensor>::typeName) {
-                writeData<sphericalTensor>(driver(),accumulations);
+                writeData<sphericalTensor>(driver(),accumulations,runTime,
+                                  name,writeCsv,writeDistributions);
             } else {
                 WarningIn(args.executable())
                     << "Don't know how to handle type " << rType
@@ -199,6 +308,12 @@
 
             Info << endl;
         }
+        Info << endl;
+    }
+
+    if(csvFiles.size()>0) {
+        Info << csvFiles.size() << " CSV files written" << endl;
+        csvFiles.clear();
     }
 
     Info << "End\n" << endl;