Index: src/Actions/AtomsCalculation.hpp
===================================================================
--- src/Actions/AtomsCalculation.hpp	(revision b54ac804770af8e83f6b370746a4c0eba37f99f5)
+++ src/Actions/AtomsCalculation.hpp	(revision b54ac804770af8e83f6b370746a4c0eba37f99f5)
@@ -0,0 +1,28 @@
+/*
+ * AtomsCalculation.hpp
+ *
+ *  Created on: Feb 19, 2010
+ *      Author: crueger
+ */
+
+#ifndef ATOMSCALCULATION_HPP_
+#define ATOMSCALCULATION_HPP_
+
+#include "Actions/Calculation.hpp"
+
+template<typename T>
+class AtomsCalculation : public Calculation<std::vector<T> >
+{
+public:
+  AtomsCalculation(boost::function<T(atom*)> op,std::string name,AtomDescriptor descr);
+  virtual ~AtomsCalculation();
+
+protected:
+  virtual std::vector<T>* doCalc();
+
+private:
+  AtomDescriptor descr;
+  boost::function<T(atom*)> op;
+};
+
+#endif /* ATOMSCALCULATION_HPP_ */
Index: src/Actions/AtomsCalculation_impl.hpp
===================================================================
--- src/Actions/AtomsCalculation_impl.hpp	(revision b54ac804770af8e83f6b370746a4c0eba37f99f5)
+++ src/Actions/AtomsCalculation_impl.hpp	(revision b54ac804770af8e83f6b370746a4c0eba37f99f5)
@@ -0,0 +1,48 @@
+/*
+ * AtomsCalculation_impl.hpp
+ *
+ *  Created on: Feb 19, 2010
+ *      Author: crueger
+ */
+
+#ifndef ATOMSCALCULATION_IMPL_HPP_
+#define ATOMSCALCULATION_IMPL_HPP_
+
+#include "Actions/AtomsCalculation.hpp"
+#include "Actions/Calculation_impl.hpp"
+
+#include <iostream>
+
+using namespace std;
+
+template<typename T>
+AtomsCalculation<T>::AtomsCalculation(boost::function<T(atom*)> _op,std::string name,AtomDescriptor _descr) :
+  Calculation<std::vector<T> >(0,name,false),
+  op(_op),
+  descr(_descr)
+{}
+
+template<typename T>
+AtomsCalculation<T>::~AtomsCalculation(){
+}
+
+template<typename T>
+std::vector<T>* AtomsCalculation<T>::doCalc(){
+  World* world = World::get();
+  int steps = world->numAtoms();
+  int count = 0;
+  std::vector<T> *res = new std::vector<T>();
+  res->reserve(steps);
+  Process::setMaxSteps(steps);
+  Process::start();
+  World::AtomIterator iter;
+  for(iter=world->getAtomIter(descr);iter!=world->atomEnd();++iter){
+    Process::setCurrStep(iter.getCount());
+    res->push_back(op(*iter));
+  }
+  Process::stop();
+  return res;
+}
+
+
+#endif /* ATOMSCALCULATION_IMPL_HPP_ */
Index: src/Actions/Calculation.hpp
===================================================================
--- src/Actions/Calculation.hpp	(revision afb47f9975466cee3a9f4f362aa7bf8f6944ffd4)
+++ src/Actions/Calculation.hpp	(revision b54ac804770af8e83f6b370746a4c0eba37f99f5)
@@ -12,5 +12,5 @@
 
 template<typename T>
-class Calculation: public Process
+class Calculation : public Process
 {
 public:
@@ -22,5 +22,5 @@
   virtual bool canUndo();
 
-  virtual void calc();
+  virtual T operator()();
   virtual bool hasResult();
   virtual T getResult();
Index: src/Actions/Calculation_impl.hpp
===================================================================
--- src/Actions/Calculation_impl.hpp	(revision afb47f9975466cee3a9f4f362aa7bf8f6944ffd4)
+++ src/Actions/Calculation_impl.hpp	(revision b54ac804770af8e83f6b370746a4c0eba37f99f5)
@@ -9,8 +9,10 @@
 #define CALCULATION_IMPL_HPP_
 
+#include "Actions/Calculation.hpp"
+
 #include <cassert>
 
 template<typename T>
-Calculation<T>::Calculation(int _maxSteps, std::string _name, bool _doRegister=true) :
+Calculation<T>::Calculation(int _maxSteps, std::string _name, bool _doRegister) :
   Process(_maxSteps,_name,_doRegister),
   done(false),
@@ -20,5 +22,7 @@
 template<typename T>
 Calculation<T>::~Calculation()
-{}
+{
+  delete result;
+}
 
 // methods inherited from Action
@@ -26,5 +30,6 @@
 template<typename T>
 void Calculation<T>::call(){
-  calc();
+  reset();
+  (*this)();
 }
 
@@ -41,9 +46,10 @@
 
 template<typename T>
-void Calculation<T>::calc(){
+T Calculation<T>::operator()(){
   if(!done){
     result = doCalc();
     done = true;
   }
+  return *result;
 }
 
@@ -62,4 +68,5 @@
 void Calculation<T>::reset(){
   done = false;
+  delete result;
   result = 0;
 }
Index: src/World.hpp
===================================================================
--- src/World.hpp	(revision afb47f9975466cee3a9f4f362aa7bf8f6944ffd4)
+++ src/World.hpp	(revision b54ac804770af8e83f6b370746a4c0eba37f99f5)
@@ -28,11 +28,16 @@
 class AtomDescriptor_impl;
 class ManipulateAtomsProcess;
+template<typename T>
+class AtomsCalculation;
 
 class World : public Observable
 {
+// necessary for coupling with descriptors
 friend class AtomDescriptor_impl;
 friend class AtomDescriptor;
 
+// Actions, calculations etc associated with the World
 friend class ManipulateAtomsProcess;
+template<typename> friend class AtomsCalculation;
 
 typedef std::map<int,atom*> AtomList;
@@ -44,4 +49,8 @@
   atom* getAtom(AtomDescriptor descriptor);
   std::vector<atom*> getAllAtoms(AtomDescriptor descriptor);
+
+  template<typename T>
+  AtomsCalculation<T>* calcOnAtoms(boost::function<T(atom*)>,std::string,AtomDescriptor);
+
   int numAtoms();
   int numMolecules();
Index: src/World_calculations.hpp
===================================================================
--- src/World_calculations.hpp	(revision b54ac804770af8e83f6b370746a4c0eba37f99f5)
+++ src/World_calculations.hpp	(revision b54ac804770af8e83f6b370746a4c0eba37f99f5)
@@ -0,0 +1,20 @@
+/*
+ * World_calculations.hpp
+ *
+ *  Created on: Feb 19, 2010
+ *      Author: crueger
+ */
+
+#ifndef WORLD_CALCULATIONS_HPP_
+#define WORLD_CALCULATIONS_HPP_
+
+
+#include "World.hpp"
+#include "Actions/AtomsCalculation.hpp"
+
+template<typename T>
+AtomsCalculation<T>* World::calcOnAtoms(boost::function<T(atom*)> op,std::string name,AtomDescriptor descr){
+  return new AtomsCalculation<T>(op,name,descr);
+}
+
+#endif /* WORLD_CALCULATIONS_HPP_ */
Index: src/unittests/Makefile.am
===================================================================
--- src/unittests/Makefile.am	(revision afb47f9975466cee3a9f4f362aa7bf8f6944ffd4)
+++ src/unittests/Makefile.am	(revision b54ac804770af8e83f6b370746a4c0eba37f99f5)
@@ -31,4 +31,5 @@
   DescriptorUnittest \
   manipulateAtomsTest \
+  atomsCalculationTest \
   ${MENUTESTS}  
     
@@ -115,4 +116,7 @@
 manipulateAtomsTest_LDADD = ${ALLLIBS}
 
+atomsCalculationTest_SOURCES = atomsCalculationTest.cpp atomsCalculationTest.hpp
+atomsCalculationTest_LDADD = ${ALLLIBS}
+
 #AUTOMAKE_OPTIONS = parallel-tests
 
Index: src/unittests/atomsCalculationTest.cpp
===================================================================
--- src/unittests/atomsCalculationTest.cpp	(revision b54ac804770af8e83f6b370746a4c0eba37f99f5)
+++ src/unittests/atomsCalculationTest.cpp	(revision b54ac804770af8e83f6b370746a4c0eba37f99f5)
@@ -0,0 +1,140 @@
+/*
+ * atomsCalculationTest.cpp
+ *
+ *  Created on: Feb 19, 2010
+ *      Author: crueger
+ */
+
+#include "atomsCalculationTest.hpp"
+
+#include <cppunit/CompilerOutputter.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/ui/text/TestRunner.h>
+#include <iostream>
+#include <boost/bind.hpp>
+
+#include "Descriptors/AtomDescriptor.hpp"
+#include "Descriptors/AtomIdDescriptor.hpp"
+#include "Actions/AtomsCalculation.hpp"
+#include "Actions/AtomsCalculation_impl.hpp"
+#include "Actions/ActionRegistry.hpp"
+
+#include "World.hpp"
+#include "World_calculations.hpp"
+#include "atom.hpp"
+
+// Registers the fixture into the 'registry'
+CPPUNIT_TEST_SUITE_REGISTRATION( atomsCalculationTest );
+
+// some stubs
+class AtomStub : public atom {
+public:
+  AtomStub(int _id) :
+  atom(),
+  id(_id),
+  manipulated(false)
+  {}
+
+  virtual int getId(){
+    return id;
+  }
+
+  virtual void doSomething(){
+    manipulated = true;
+  }
+
+  bool manipulated;
+private:
+  int id;
+};
+
+// set up and tear down
+void atomsCalculationTest::setUp(){
+  World::get();
+  for(int i=0;i<ATOM_COUNT;++i){
+    atoms[i]= new AtomStub(i);
+  }
+}
+void atomsCalculationTest::tearDown(){
+  World::destroy();
+  for(int i=0;i<ATOM_COUNT;++i){
+    delete atoms[i];
+  }
+  ActionRegistry::purgeRegistry();
+}
+
+// some helper functions
+bool hasAll(std::vector<int> ids,int min, int max, std::set<int> excluded = std::set<int>()){
+  for(int i=min;i<max;++i){
+    if(!excluded.count(i)){
+      std::vector<int>::iterator iter;
+      bool res=false;
+      for(iter=ids.begin();iter!=ids.end();++iter){
+        res |= (*iter) == i;
+      }
+      if(!res) {
+        cout << "Atom " << i << " missing in returned list" << endl;
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+bool hasNoDuplicates(std::vector<int> ids){
+  std::set<int> found;
+  std::vector<int>::iterator iter;
+  for(iter=ids.begin();iter!=ids.end();++iter){
+    int id = (*iter);
+    if(found.count(id))
+      return false;
+    found.insert(id);
+  }
+  return true;
+}
+
+void operation(atom* _atom){
+  AtomStub *atom = dynamic_cast<AtomStub*>(_atom);
+  assert(atom);
+  atom->doSomething();
+}
+
+
+void atomsCalculationTest::testCalculateSimple(){
+  AtomsCalculation<int> *calc = World::get()->calcOnAtoms<int>(boost::bind(&atom::getId,_1),"FOO",AllAtoms());
+  std::vector<int> allIds = (*calc)();
+  CPPUNIT_ASSERT(hasAll(allIds,0,ATOM_COUNT));
+  CPPUNIT_ASSERT(hasNoDuplicates(allIds));
+}
+
+void atomsCalculationTest::testCalculateExcluded(){
+  int excluded = ATOM_COUNT/2;
+  AtomsCalculation<int> *calc = World::get()->calcOnAtoms<int>(boost::bind(&atom::getId,_1),"FOO",AllAtoms() && !AtomById(excluded));
+  std::vector<int> allIds = (*calc)();
+  std::set<int> excluded_set;
+  excluded_set.insert(excluded);
+  CPPUNIT_ASSERT(hasAll(allIds,0,ATOM_COUNT,excluded_set));
+  CPPUNIT_ASSERT(hasNoDuplicates(allIds));
+  CPPUNIT_ASSERT_EQUAL((size_t)(ATOM_COUNT-1),allIds.size());
+}
+
+/********************************************** Main routine **************************************/
+
+int main(int argc, char **argv)
+{
+  // Get the top level suite from the registry
+  CppUnit::Test *suite = CppUnit::TestFactoryRegistry::getRegistry().makeTest();
+
+  // Adds the test to the list of test to run
+  CppUnit::TextUi::TestRunner runner;
+  runner.addTest( suite );
+
+  // Change the default outputter to a compiler error format outputter
+  runner.setOutputter( new CppUnit::CompilerOutputter( &runner.result(),
+                                                       std::cerr ) );
+  // Run the tests.
+  bool wasSucessful = runner.run();
+
+  // Return error code 1 if the one of test failed.
+  return wasSucessful ? 0 : 1;
+};
Index: src/unittests/atomsCalculationTest.hpp
===================================================================
--- src/unittests/atomsCalculationTest.hpp	(revision b54ac804770af8e83f6b370746a4c0eba37f99f5)
+++ src/unittests/atomsCalculationTest.hpp	(revision b54ac804770af8e83f6b370746a4c0eba37f99f5)
@@ -0,0 +1,35 @@
+/*
+ * atomsCalculationTest.hpp
+ *
+ *  Created on: Feb 19, 2010
+ *      Author: crueger
+ */
+
+#ifndef ATOMSCALCULATIONTEST_HPP_
+#define ATOMSCALCULATIONTEST_HPP_
+
+#include <cppunit/extensions/HelperMacros.h>
+
+#define ATOM_COUNT (10)
+
+class atom;
+
+class atomsCalculationTest :  public CppUnit::TestFixture
+{
+  CPPUNIT_TEST_SUITE( atomsCalculationTest );
+  CPPUNIT_TEST ( testCalculateSimple );
+  CPPUNIT_TEST ( testCalculateExcluded );
+  CPPUNIT_TEST_SUITE_END();
+
+public:
+  void setUp();
+  void tearDown();
+
+  void testCalculateSimple();
+  void testCalculateExcluded();
+
+private:
+  atom *atoms [ATOM_COUNT];
+};
+
+#endif /* ATOMSCALCULATIONTEST_HPP_ */
Index: src/unittests/manipulateAtomsTest.cpp
===================================================================
--- src/unittests/manipulateAtomsTest.cpp	(revision afb47f9975466cee3a9f4f362aa7bf8f6944ffd4)
+++ src/unittests/manipulateAtomsTest.cpp	(revision b54ac804770af8e83f6b370746a4c0eba37f99f5)
@@ -7,6 +7,4 @@
 
 #include "manipulateAtomsTest.hpp"
-
-#include "DescriptorUnittest.hpp"
 
 #include <cppunit/CompilerOutputter.h>
