Index: src/Actions/FragmentationAction/FragmentationAutomationAction.cpp
===================================================================
--- src/Actions/FragmentationAction/FragmentationAutomationAction.cpp	(revision f20da52f1db9ff211bd8cc8dd78121b43459ef0d)
+++ src/Actions/FragmentationAction/FragmentationAutomationAction.cpp	(revision d61161337b5ad56815ad99afc6755e5991c31abd)
@@ -39,4 +39,7 @@
 #include "CodePatterns/MemDebug.hpp"
 
+#include <boost/assign.hpp>
+
+#include "CodePatterns/Assert.hpp"
 #include "CodePatterns/Info.hpp"
 #include "CodePatterns/Log.hpp"
@@ -48,8 +51,14 @@
 #include "Fragmentation/ForceMatrix.hpp"
 #include "Fragmentation/Fragmentation.hpp"
+#include "Fragmentation/SetValues/Histogram.hpp"
+#include "Fragmentation/SetValues/IndexedVectors.hpp"
 #include "Fragmentation/HydrogenSaturation_enum.hpp"
+#include "Fragmentation/KeySet.hpp"
 #include "Fragmentation/KeySetsContainer.hpp"
+#include "Fragmentation/Summation/printSum.hpp"
 #include "Graph/DepthFirstSearchAnalysis.hpp"
-#include "Jobs/MPQCCommandJob.hpp"
+#include "Jobs/MPQCJob.hpp"
+#include "Jobs/MPQCData.hpp"
+#include "Jobs/MPQCData_printKeyNames.hpp"
 #include "molecule.hpp"
 #include "World.hpp"
@@ -59,7 +68,11 @@
 #include <vector>
 
+#include <boost/mpl/for_each.hpp>
+
 #include "Actions/FragmentationAction/FragmentationAutomationAction.hpp"
 
 using namespace MoleCuilder;
+
+using namespace boost::assign;
 
 // and construct the stuff
@@ -94,5 +107,5 @@
   std::string output((std::istreambuf_iterator<char>(file)),
       std::istreambuf_iterator<char>());
-  FragmentJob::ptr testJob( new MPQCCommandJob(output, nextid, command) );
+  FragmentJob::ptr testJob( new MPQCJob(nextid, output) );
   jobs.push_back(testJob);
   file.close();
@@ -145,5 +158,4 @@
   ForceMatrix Force;
   ForceMatrix ForceFragments;
-  KeySetsContainer KeySet;
 
   // align fragments
@@ -190,5 +202,5 @@
       MatrixContainer::MatrixArray matrix;
       matrix.resize(1);
-      matrix[0].resize(1, extractedData.energy);
+      matrix[0].resize(1, extractedData.energies.total);
       if (!Energy.AddMatrix(
           std::string("MPQCJob ")+toString((*iter)->getId()),
@@ -234,12 +246,130 @@
     return false;
 
+  // initialise indices
+  KeySetsContainer KeySet;
+  if (!Energy.InitialiseIndices()) return false;
+
+  if (!Force.ParseIndices(KeySetFilename.c_str())) return false;
+
+  if (!KeySet.ParseKeySets(KeySetFilename.c_str(), Force.RowCounter, Force.MatrixCounter)) return false;
+
+  /// prepare for OrthogonalSummation
+
+  // gather all present indices in AllIndices
+  IndexSet::ptr AllIndices(new IndexSet);
+  for (KeySetsContainer::ArrayOfIntVectors::const_iterator iter = KeySet.KeySets.begin();
+      iter != KeySet.KeySets.end(); ++iter)
+    for(KeySetsContainer::IntVector::const_iterator keyiter = (*iter).begin();
+        keyiter != (*iter).end(); ++keyiter) {
+      if (*keyiter != -1)
+        (*AllIndices) += *keyiter;
+    }
+  LOG(1, "INFO: AllIndices is " << AllIndices << ".");
+  // create container with all keysets
+  IndexSetContainer::ptr container(new IndexSetContainer(AllIndices));
+  for (KeySetsContainer::ArrayOfIntVectors::const_iterator iter = KeySet.KeySets.begin();
+      iter != KeySet.KeySets.end(); ++iter) {
+    IndexSet tempset;
+    for(KeySetsContainer::IntVector::const_iterator keyiter = (*iter).begin();
+        keyiter != (*iter).end(); ++keyiter)
+      if (*keyiter != -1)
+        tempset += *keyiter;
+    container->insert(tempset);
+  }
+  // create the map of all keysets
+  SubsetMap::ptr subsetmap(new SubsetMap(*container));
+
+  /// convert all MPQCData to MPQCDataMap_t
+  {
+    // energy_t
+    std::vector<MPQCDataEnergyMap_t> MPQCData_Energy_fused;
+    MPQCData_Energy_fused.reserve(fragmentData.size());
+    for(std::vector<MPQCData>::const_iterator dataiter = fragmentData.begin();
+        dataiter != fragmentData.end(); ++dataiter) {
+      const MPQCData &extractedData = *dataiter;
+      LOG(2, "DEBUG: Current extracted Data is " << extractedData << ".");
+      MPQCDataEnergyMap_t instance;
+      boost::fusion::at_key<MPQCDataFused::energy_total>(instance) = extractedData.energies.total;
+      boost::fusion::at_key<MPQCDataFused::energy_nuclear_repulsion>(instance) = extractedData.energies.nuclear_repulsion;
+      boost::fusion::at_key<MPQCDataFused::energy_electron_coulomb>(instance) = extractedData.energies.electron_coulomb;
+      boost::fusion::at_key<MPQCDataFused::energy_electron_exchange>(instance) = extractedData.energies.electron_exchange;
+      boost::fusion::at_key<MPQCDataFused::energy_correlation>(instance) = extractedData.energies.correlation;
+      boost::fusion::at_key<MPQCDataFused::energy_overlap>(instance) = extractedData.energies.overlap;
+      boost::fusion::at_key<MPQCDataFused::energy_kinetic>(instance) = extractedData.energies.kinetic;
+      boost::fusion::at_key<MPQCDataFused::energy_hcore>(instance) = extractedData.energies.hcore;
+      boost::fusion::at_key<MPQCDataFused::energy_eigenvalues>(instance) = extractedData.energies.eigenvalues;
+      MPQCData_Energy_fused.push_back(instance);
+    }
+
+    // forces
+    const IndexSetContainer::Container_t &indices = container->getContainer();
+    ASSERT( indices.size() == fragmentData.size(),
+        "FragmentationAutomationAction::performCall() - indices and fragmentData differ in size.");
+    std::vector<MPQCDataForceMap_t> MPQCData_Force_fused;
+    MPQCData_Force_fused.reserve(fragmentData.size());
+    std::vector<MPQCData>::const_iterator dataiter = fragmentData.begin();
+    IndexSetContainer::Container_t::const_iterator indexiter = indices.begin();
+    for(;dataiter != fragmentData.end(); ++dataiter, ++indexiter) {
+      const MPQCData &extractedData = *dataiter;
+      LOG(2, "DEBUG: Current extracted Data is " << extractedData << ".");
+      MPQCDataForceMap_t instance;
+      boost::fusion::at_key<MPQCDataFused::forces>(instance) =
+          IndexedVectors(**indexiter, extractedData.forces);
+      MPQCData_Force_fused.push_back(instance);
+    }
+
+    // times
+    std::vector<MPQCDataTimeMap_t> MPQCData_Time_fused;
+    MPQCData_Time_fused.reserve(fragmentData.size());
+    for(std::vector<MPQCData>::const_iterator dataiter = fragmentData.begin();
+        dataiter != fragmentData.end(); ++dataiter) {
+      const MPQCData &extractedData = *dataiter;
+      LOG(2, "DEBUG: Current extracted Data is " << extractedData << ".");
+      MPQCDataTimeMap_t instance;
+      boost::fusion::at_key<MPQCDataFused::times_walltime>(instance) = extractedData.times.walltime;
+      boost::fusion::at_key<MPQCDataFused::times_cputime>(instance) = extractedData.times.cputime;
+      boost::fusion::at_key<MPQCDataFused::times_flops>(instance) = extractedData.times.flops;
+      MPQCData_Time_fused.push_back(instance);
+    }
+
+    // create a vector of all job ids
+    std::vector<JobId_t> jobids(results.size(), JobId::IllegalJob);
+    std::transform(results.begin(), results.end(), jobids.begin(),
+        boost::bind(&FragmentResult::getId,
+            boost::bind(&FragmentResult::ptr::operator->, _1)));
+
+    // sum up and print energies
+    boost::mpl::for_each<MPQCDataEnergyVector_t>(
+        printSum<MPQCDataEnergyMap_t>(
+            subsetmap,
+            MPQCData_Energy_fused,
+            jobids,
+            container->getContainer(),
+            MatrixNrLookup)
+        );
+
+    // sum up and print forces
+    boost::mpl::for_each<MPQCDataForceVector_t>(
+        printSum<MPQCDataForceMap_t>(
+            subsetmap,
+            MPQCData_Force_fused,
+            jobids,
+            container->getContainer(),
+            MatrixNrLookup)
+        );
+
+    // TODO: Times should just be summed not orthogonalized
+//    // sum up and print times
+//    boost::mpl::for_each<MPQCDataTimeVector_t>(
+//        printSum<MPQCDataTimeMap_t>(
+//            subsetmap,
+//            MPQCData_Time_fused,
+//            jobids,
+//            container->getContainer(),
+//            MatrixNrLookup)
+//        );
+  }
 
   // combine all found data
-  if (!Energy.InitialiseIndices()) return false;
-
-  if (!Force.ParseIndices(KeySetFilename.c_str())) return false;
-
-  if (!KeySet.ParseKeySets(KeySetFilename.c_str(), Force.RowCounter, Force.MatrixCounter)) return false;
-
   if (!KeySet.ParseManyBodyTerms()) return false;
 
@@ -275,45 +405,56 @@
 }
 
-Action::state_ptr FragmentationFragmentationAutomationAction::performCall() {
-  boost::asio::io_service io_service;
-  FragmentController controller(io_service);
-
-  // TODO: Have io_service run in second thread and merge with current again eventually
-
-  // Phase One: obtain ids
-  std::vector< boost::filesystem::path > jobfiles = params.jobfiles.get();
-  controller.requestIds(params.host.get(), params.port.get(), jobfiles.size());
-  {
-    io_service.reset();
-    Info info("io_service: Phase One");
-    io_service.run();
-  }
-  // Phase Two: create and add jobs
-  {
-    std::vector<FragmentJob::ptr> jobs;
-    for (std::vector< boost::filesystem::path >::const_iterator iter = jobfiles .begin();
-        iter != jobfiles .end(); ++iter) {
-      const std::string &filename = (*iter).string();
-      if (boost::filesystem::exists(filename)) {
-        const JobId_t next_id = controller.getAvailableId();
-        LOG(1, "INFO: Creating MPQCCommandJob with filename'"
-            +filename+"', and id "+toString(next_id)+".");
-        parsejob(jobs, params.executable.get().string(), filename, next_id);
-      } else {
-        ELOG(1, "Fragment job "+filename+" does not exist.");
-        return Action::failure;
-      }
-    }
-    controller.addJobs(jobs);
-    controller.sendJobs(params.host.get(), params.port.get());
-  }
-  {
-    io_service.reset();
-    Info info("io_service: Phase Two");
-    io_service.run();
-  }
-  // Phase Three: calculate result
+
+void RunService(
+    boost::asio::io_service &io_service,
+    std::string message)
+{
+  message = std::string("io_service: ") + message;
+  io_service.reset();
+  Info info(message.c_str());
+  io_service.run();
+}
+
+void requestIds(
+    FragmentController &controller,
+    const FragmentationFragmentationAutomationAction::FragmentationFragmentationAutomationParameters &params,
+    const size_t numberjobs)
+{
+  controller.requestIds(params.host.get(), params.port.get(), numberjobs);
+}
+
+bool createJobsFromFiles(
+    FragmentController &controller,
+    const FragmentationFragmentationAutomationAction::FragmentationFragmentationAutomationParameters &params,
+    const std::vector< boost::filesystem::path > &jobfiles)
+{
+  std::vector<FragmentJob::ptr> jobs;
+  for (std::vector< boost::filesystem::path >::const_iterator iter = jobfiles.begin();
+      iter != jobfiles .end(); ++iter) {
+    const std::string &filename = (*iter).string();
+    if (boost::filesystem::exists(filename)) {
+      const JobId_t next_id = controller.getAvailableId();
+      LOG(1, "INFO: Creating MPQCCommandJob with filename'"
+          +filename+"', and id "+toString(next_id)+".");
+      parsejob(jobs, params.executable.get().string(), filename, next_id);
+    } else {
+      ELOG(1, "Fragment job "+filename+" does not exist.");
+      return false;
+    }
+  }
+  controller.addJobs(jobs);
+  controller.sendJobs(params.host.get(), params.port.get());
+  return true;
+}
+
+void WaitforResults(
+    boost::asio::io_service &io_service,
+    FragmentController &controller,
+    const FragmentationFragmentationAutomationAction::FragmentationFragmentationAutomationParameters &params,
+    const size_t NoExpectedResults
+    )
+{
   size_t NoCalculatedResults = 0;
-  while (NoCalculatedResults != jobfiles.size()) {
+  while (NoCalculatedResults != NoExpectedResults) {
     // wait a bit
     boost::asio::deadline_timer timer(io_service);
@@ -322,20 +463,36 @@
     // then request status
     controller.checkResults(params.host.get(), params.port.get());
-    {
-      io_service.reset();
-      Info info("io_service: Phase Three");
-      io_service.run();
-    }
+    RunService(io_service, "Checking on results");
+
     const std::pair<size_t, size_t> JobStatus = controller.getJobStatus();
     LOG(1, "INFO: #" << JobStatus.first << " are waiting in the queue and #" << JobStatus.second << " jobs are calculated so far.");
     NoCalculatedResults = JobStatus.second;
   }
+}
+
+
+Action::state_ptr FragmentationFragmentationAutomationAction::performCall() {
+  boost::asio::io_service io_service;
+  FragmentController controller(io_service);
+
+  // TODO: Have io_service run in second thread and merge with current again eventually
+
+  // Phase One: obtain ids
+  std::vector< boost::filesystem::path > jobfiles = params.jobfiles.get();
+  requestIds(controller, params, jobfiles.size());
+  RunService(io_service, "Requesting ids");
+
+  // Phase Two: create and add jobs
+  if (!createJobsFromFiles(controller, params, jobfiles))
+    return Action::failure;
+  RunService(io_service, "Adding jobs");
+
+  // Phase Three: calculate result
+  WaitforResults(io_service, controller, params, jobfiles.size());
+
   // Phase Three: get result
   controller.receiveResults(params.host.get(), params.port.get());
-  {
-    io_service.reset();
-    Info info("io_service: Phase Four");
-    io_service.run();
-  }
+  RunService(io_service, "Phase Four");
+
   // Final phase: print result
   {
