From 91d7a59e365b766b5122100e16f226d5d0dbf75e Mon Sep 17 00:00:00 2001
From: Martin Hierholzer <martin.hierholzer@desy.de>
Date: Wed, 24 Aug 2022 17:46:28 +0200
Subject: [PATCH] move inline implementations out of line

---
 include/Application.h                         |  56 +--
 include/ApplicationModule.h                   |  17 +-
 include/ArrayAccessor.h                       | 175 +++++---
 include/ConstantAccessor.h                    |  64 +--
 include/ConsumingFanOut.h                     |  92 ++--
 include/ControlSystemModule.h                 |   7 +-
 include/DebugPrintAccessorDecorator.h         |  76 ++--
 include/DeviceModule.h                        |  52 +--
 include/EntityOwner.h                         |  17 +-
 include/FanOut.h                              | 123 +++---
 include/FeedingFanOut.h                       | 394 +++++++++++-------
 include/Flags.h                               |  12 +
 include/InternalModule.h                      |  36 +-
 include/InversionOfControlAccessor.h          | 137 ++++--
 .../MetaDataPropagatingRegisterDecorator.h    |  12 +-
 include/Module.h                              |  26 +-
 include/ModuleGroup.h                         |   8 +-
 include/ModuleImpl.h                          |  16 +-
 include/ScalarAccessor.h                      | 162 +++++--
 include/SupportedUserTypes.h                  |   8 +
 include/TestFacility.h                        | 382 ++++++++---------
 include/TestableModeAccessorDecorator.h       | 276 +++++++-----
 include/ThreadedFanOut.h                      | 301 +++++++------
 include/TriggerFanOut.h                       | 128 ++----
 include/VariableGroup.h                       |  15 +-
 include/VariableNetwork.h                     |   6 +-
 include/VariableNetworkDumpingVisitor.h       |   6 +
 include/VariableNetworkGraphDumpingVisitor.h  |   7 +-
 ...VariableNetworkModuleGraphDumpingVisitor.h |   7 +-
 include/VariableNetworkNode.h                 |  27 +-
 include/VariableNetworkNodeDumpingVisitor.h   |   8 +
 include/VirtualModule.h                       |   7 +-
 include/Visitor.h                             |  13 +-
 include/VoidAccessor.h                        |  63 ++-
 include/XMLGeneratorVisitor.h                 |   6 +
 src/Application.cc                            |  42 ++
 src/ApplicationModule.cc                      |  15 +
 src/ControlSystemModule.cc                    |   9 +
 src/DebugPrintAccessorDecorator.cc            |  89 ++++
 src/DeviceModule.cc                           |  84 +++-
 src/EntityOwner.cc                            |  55 ++-
 src/Module.cc                                 |  22 +
 src/ModuleGroup.cc                            |  13 +
 src/ModuleImpl.cc                             |  21 +
 src/TestFacility.cc                           | 131 ++++++
 src/TriggerFanOut.cc                          | 116 ++++++
 src/VariableGroup.cc                          |  13 +
 src/VariableNetwork.cc                        |  11 +
 src/VariableNetworkDumpingVisitor.cc          |   6 +
 src/VariableNetworkGraphDumpingVisitor.cc     |  11 +
 src/VariableNetworkNodeDumpingVisitor.cc      |   6 +
 src/VirtualModule.cc                          |  37 +-
 src/VisitorHelper.cc                          |   6 +
 src/XMLGeneratorVisitor.cc                    |  11 +
 54 files changed, 2192 insertions(+), 1248 deletions(-)
 create mode 100644 src/DebugPrintAccessorDecorator.cc
 create mode 100644 src/TestFacility.cc
 create mode 100644 src/TriggerFanOut.cc

diff --git a/include/Application.h b/include/Application.h
index a070f77b..12f85912 100644
--- a/include/Application.h
+++ b/include/Application.h
@@ -13,10 +13,11 @@
 
 #include <atomic>
 #include <mutex>
-//#include "DeviceModule.h"
 
 namespace ChimeraTK {
 
+  /*********************************************************************************************************************/
+
   class Module;
   class AccessorBase;
   class VariableNetwork;
@@ -32,6 +33,8 @@ namespace ChimeraTK {
   template<typename UserType>
   class ConsumingFanOut;
 
+  /*********************************************************************************************************************/
+
   class Application : public ApplicationBase, public EntityOwner {
    public:
     /** The constructor takes the application name as an argument. The name must
@@ -96,11 +99,7 @@ namespace ChimeraTK {
      *  Note: Enabling the testable mode will have a singificant impact on the
      * performance, since it will prevent any module threads to run at the same
      * time! */
-    void enableTestableMode() {
-      threadName() = "TEST THREAD";
-      testableMode = true;
-      testableModeLock("enableTestableMode");
-    }
+    void enableTestableMode();
 
     /**
      * Returns true if application is in testable mode else returns
@@ -146,10 +145,7 @@ namespace ChimeraTK {
     /** Test if the testable mode mutex is locked by the current thread.
      *
      *  This function should generally not be used in user code. */
-    static bool testableModeTestLock() {
-      if(!getInstance().testableMode) return false;
-      return getTestableModeLockObject().owns_lock();
-    }
+    static bool testableModeTestLock();
 
     /** Set string holding the name of the current thread or the specified thread ID. This is used e.g. for
      *  debugging output of the testable mode and for the internal profiler. */
@@ -163,11 +159,7 @@ namespace ChimeraTK {
     /** Register the thread in the application system and give it a name. This
      * should be done for all threads used by the application to help with
      * debugging and to allow profiling. */
-    static void registerThread(const std::string& name) {
-      Application::getInstance().setThreadName(name);
-      Profiler::registerThread(name);
-      pthread_setname_np(pthread_self(), name.substr(0, std::min<std::string::size_type>(name.length(), 15)).c_str());
-    }
+    static void registerThread(const std::string& name);
 
     void debugMakeConnections() { enableDebugMakeConnections = true; };
 
@@ -197,27 +189,14 @@ namespace ChimeraTK {
     void enableDebugDataLoss() { debugDataLoss = true; }
 
     /** Incremenet counter for how many write() operations have overwritten unread data */
-    static void incrementDataLossCounter(const std::string& name) {
-      if(getInstance().debugDataLoss) {
-        std::cout << "Data loss in variable " << name << std::endl;
-      }
-      getInstance().dataLossCounter++;
-    }
+    static void incrementDataLossCounter(const std::string& name);
 
-    static size_t getAndResetDataLossCounter() {
-      size_t counter = getInstance().dataLossCounter.load(std::memory_order_relaxed);
-      while(!getInstance().dataLossCounter.compare_exchange_weak(
-          counter, 0, std::memory_order_release, std::memory_order_relaxed))
-        ;
-      return counter;
-    }
+    static size_t getAndResetDataLossCounter();
 
     /** Convenience function for creating constants. See
      * VariableNetworkNode::makeConstant() for details. */
     template<typename UserType>
-    static VariableNetworkNode makeConstant(UserType value, size_t length = 1, bool makeFeeder = true) {
-      return VariableNetworkNode::makeConstant(makeFeeder, value, length);
-    }
+    static VariableNetworkNode makeConstant(UserType value, size_t length = 1, bool makeFeeder = true);
 
     void registerDeviceModule(DeviceModule* deviceModule);
     void unregisterDeviceModule(DeviceModule* deviceModule);
@@ -515,10 +494,8 @@ namespace ChimeraTK {
     std::mutex m_threadNames;
 
     template<typename UserType>
-    friend class TestableModeAccessorDecorator; // needs access to the
-                                                // testableMode_mutex and
-                                                // testableMode_counter and the
-                                                // idMap
+    friend class
+        TestableModeAccessorDecorator; // needs access to the testableMode_mutex and testableMode_counter and the idMap
 
     friend class TestFacility;  // needs access to testableMode_variables
     friend class DeviceModule;  // needs access to testableMode_variables
@@ -562,4 +539,13 @@ namespace ChimeraTK {
     }
   };
 
+  /*********************************************************************************************************************/
+
+  template<typename UserType>
+  VariableNetworkNode Application::makeConstant(UserType value, size_t length, bool makeFeeder) {
+    return VariableNetworkNode::makeConstant(makeFeeder, value, length);
+  }
+
+  /*********************************************************************************************************************/
+
 } /* namespace ChimeraTK */
diff --git a/include/ApplicationModule.h b/include/ApplicationModule.h
index 30077027..ed5ea5df 100644
--- a/include/ApplicationModule.h
+++ b/include/ApplicationModule.h
@@ -11,10 +11,14 @@
 
 namespace ChimeraTK {
 
+  /*********************************************************************************************************************/
+
   class Application;
   class ModuleGroup;
   struct ConfigReader;
 
+  /*********************************************************************************************************************/
+
   class ApplicationModule : public ModuleImpl {
    public:
     /** Constructor: Create ApplicationModule by the given name with the given description and register it with its
@@ -44,12 +48,7 @@ namespace ChimeraTK {
     ApplicationModule(ApplicationModule&& other) { operator=(std::move(other)); }
 
     /** Move assignment */
-    ApplicationModule& operator=(ApplicationModule&& other) {
-      assert(!moduleThread.joinable()); // if the thread is already running,
-                                        // moving is no longer allowed!
-      ModuleImpl::operator=(std::move(other));
-      return *this;
-    }
+    ApplicationModule& operator=(ApplicationModule&& other);
 
     /** Destructor */
     virtual ~ApplicationModule();
@@ -71,9 +70,7 @@ namespace ChimeraTK {
     void incrementDataFaultCounter() override;
     void decrementDataFaultCounter() override;
 
-    void setCurrentVersionNumber(VersionNumber versionNumber) override {
-      if(versionNumber > currentVersionNumber) currentVersionNumber = versionNumber;
-    }
+    void setCurrentVersionNumber(VersionNumber versionNumber) override;
 
     std::list<EntityOwner*> getInputModulesRecursively(std::list<EntityOwner*> startList) override;
 
@@ -115,4 +112,6 @@ namespace ChimeraTK {
     detail::CircularDependencyDetectionRecursionStopper _recursionStopper;
   };
 
+  /*********************************************************************************************************************/
+
 } /* namespace ChimeraTK */
diff --git a/include/ArrayAccessor.h b/include/ArrayAccessor.h
index ab3d2e73..0ad95039 100644
--- a/include/ArrayAccessor.h
+++ b/include/ArrayAccessor.h
@@ -32,52 +32,29 @@ namespace ChimeraTK {
     using ChimeraTK::OneDRegisterAccessor<UserType>::operator=;
 
     /** Move constructor */
-    ArrayAccessor(ArrayAccessor<UserType>&& other) {
-      InversionOfControlAccessor<ArrayAccessor<UserType>>::replace(std::move(other));
-    }
+    ArrayAccessor(ArrayAccessor<UserType>&& other);
 
     /** Move assignment */
-    ArrayAccessor<UserType>& operator=(ArrayAccessor<UserType>&& other) {
-      // Having a move-assignment operator is required to use the move-assignment
-      // operator of a module containing an accessor.
-      InversionOfControlAccessor<ArrayAccessor<UserType>>::replace(std::move(other));
-      return *this;
-    }
+    ArrayAccessor<UserType>& operator=(ArrayAccessor<UserType>&& other);
 
     bool write(ChimeraTK::VersionNumber versionNumber) = delete;
     bool writeDestructively(ChimeraTK::VersionNumber versionNumber) = delete;
     void writeIfDifferent(const std::vector<UserType>& newValue, VersionNumber versionNumber) = delete;
 
-    bool write() {
-      auto versionNumber = this->getOwner()->getCurrentVersionNumber();
-      bool dataLoss = ChimeraTK::OneDRegisterAccessor<UserType>::write(versionNumber);
-      if(dataLoss) Application::incrementDataLossCounter(this->node.getQualifiedName());
-      return dataLoss;
-    }
-
-    bool writeDestructively() {
-      auto versionNumber = this->getOwner()->getCurrentVersionNumber();
-      bool dataLoss = ChimeraTK::OneDRegisterAccessor<UserType>::writeDestructively(versionNumber);
-      if(dataLoss) Application::incrementDataLossCounter(this->node.getQualifiedName());
-      return dataLoss;
-    }
-
-    void writeIfDifferent(const std::vector<UserType>& newValue) {
-      auto versionNumber = this->getOwner()->getCurrentVersionNumber();
-      ChimeraTK::OneDRegisterAccessor<UserType>::writeIfDifferent(newValue, versionNumber);
-    }
+    bool write();
+
+    bool writeDestructively();
+
+    void writeIfDifferent(const std::vector<UserType>& newValue);
 
    protected:
     friend class InversionOfControlAccessor<ArrayAccessor<UserType>>;
 
     ArrayAccessor(Module* owner, const std::string& name, VariableDirection direction, std::string unit,
         size_t nElements, UpdateMode mode, const std::string& description,
-        const std::unordered_set<std::string>& tags = {})
-    : InversionOfControlAccessor<ArrayAccessor<UserType>>(
-          owner, name, direction, unit, nElements, mode, description, &typeid(UserType), tags) {}
+        const std::unordered_set<std::string>& tags = {});
 
-    /** Default constructor creates a dysfunctional accessor (to be assigned with
-     * a real accessor later) */
+    /** Default constructor creates a dysfunctional accessor (to be assigned with a real accessor later) */
     ArrayAccessor() {}
   };
 
@@ -87,10 +64,8 @@ namespace ChimeraTK {
   template<typename UserType>
   struct ArrayPushInput : public ArrayAccessor<UserType> {
     ArrayPushInput(Module* owner, const std::string& name, std::string unit, size_t nElements,
-        const std::string& description, const std::unordered_set<std::string>& tags = {})
-    : ArrayAccessor<UserType>(
-          owner, name, {VariableDirection::consuming, false}, unit, nElements, UpdateMode::push, description, tags) {}
-    ArrayPushInput() : ArrayAccessor<UserType>() {}
+        const std::string& description, const std::unordered_set<std::string>& tags = {});
+    ArrayPushInput() = default;
     using ArrayAccessor<UserType>::operator=;
   };
 
@@ -100,10 +75,8 @@ namespace ChimeraTK {
   template<typename UserType>
   struct ArrayPollInput : public ArrayAccessor<UserType> {
     ArrayPollInput(Module* owner, const std::string& name, std::string unit, size_t nElements,
-        const std::string& description, const std::unordered_set<std::string>& tags = {})
-    : ArrayAccessor<UserType>(
-          owner, name, {VariableDirection::consuming, false}, unit, nElements, UpdateMode::poll, description, tags) {}
-    ArrayPollInput() : ArrayAccessor<UserType>() {}
+        const std::string& description, const std::unordered_set<std::string>& tags = {});
+    ArrayPollInput() = default;
     void read() { this->readLatest(); }
     using ArrayAccessor<UserType>::operator=;
   };
@@ -114,10 +87,8 @@ namespace ChimeraTK {
   template<typename UserType>
   struct ArrayOutput : public ArrayAccessor<UserType> {
     ArrayOutput(Module* owner, const std::string& name, std::string unit, size_t nElements,
-        const std::string& description, const std::unordered_set<std::string>& tags = {})
-    : ArrayAccessor<UserType>(
-          owner, name, {VariableDirection::feeding, false}, unit, nElements, UpdateMode::push, description, tags) {}
-    ArrayOutput() : ArrayAccessor<UserType>() {}
+        const std::string& description, const std::unordered_set<std::string>& tags = {});
+    ArrayOutput() = default;
     using ArrayAccessor<UserType>::operator=;
   };
 
@@ -128,10 +99,8 @@ namespace ChimeraTK {
   template<typename UserType>
   struct ArrayPushInputWB : public ArrayAccessor<UserType> {
     ArrayPushInputWB(Module* owner, const std::string& name, std::string unit, size_t nElements,
-        const std::string& description, const std::unordered_set<std::string>& tags = {})
-    : ArrayAccessor<UserType>(
-          owner, name, {VariableDirection::consuming, true}, unit, nElements, UpdateMode::push, description, tags) {}
-    ArrayPushInputWB() : ArrayAccessor<UserType>() {}
+        const std::string& description, const std::unordered_set<std::string>& tags = {});
+    ArrayPushInputWB() = default;
     using ArrayAccessor<UserType>::operator=;
   };
 
@@ -142,13 +111,115 @@ namespace ChimeraTK {
   template<typename UserType>
   struct ArrayOutputRB : public ArrayAccessor<UserType> {
     ArrayOutputRB(Module* owner, const std::string& name, std::string unit, size_t nElements,
-        const std::string& description, const std::unordered_set<std::string>& tags = {})
-    : ArrayAccessor<UserType>(
-          owner, name, {VariableDirection::feeding, true}, unit, nElements, UpdateMode::push, description, tags) {}
-    ArrayOutputRB() : ArrayAccessor<UserType>() {}
+        const std::string& description, const std::unordered_set<std::string>& tags = {});
+    ArrayOutputRB() = default;
     using ArrayAccessor<UserType>::operator=;
   };
 
   /********************************************************************************************************************/
+  /********************************************************************************************************************/
+  /* Implementations below this point                                                                                 */
+  /********************************************************************************************************************/
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  ArrayAccessor<UserType>::ArrayAccessor(ArrayAccessor<UserType>&& other) {
+    InversionOfControlAccessor<ArrayAccessor<UserType>>::replace(std::move(other));
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  ArrayAccessor<UserType>& ArrayAccessor<UserType>::operator=(ArrayAccessor<UserType>&& other) {
+    // Having a move-assignment operator is required to use the move-assignment
+    // operator of a module containing an accessor.
+    InversionOfControlAccessor<ArrayAccessor<UserType>>::replace(std::move(other));
+    return *this;
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  bool ArrayAccessor<UserType>::write() {
+    auto versionNumber = this->getOwner()->getCurrentVersionNumber();
+    bool dataLoss = ChimeraTK::OneDRegisterAccessor<UserType>::write(versionNumber);
+    if(dataLoss) Application::incrementDataLossCounter(this->node.getQualifiedName());
+    return dataLoss;
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  bool ArrayAccessor<UserType>::writeDestructively() {
+    auto versionNumber = this->getOwner()->getCurrentVersionNumber();
+    bool dataLoss = ChimeraTK::OneDRegisterAccessor<UserType>::writeDestructively(versionNumber);
+    if(dataLoss) Application::incrementDataLossCounter(this->node.getQualifiedName());
+    return dataLoss;
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  void ArrayAccessor<UserType>::writeIfDifferent(const std::vector<UserType>& newValue) {
+    auto versionNumber = this->getOwner()->getCurrentVersionNumber();
+    ChimeraTK::OneDRegisterAccessor<UserType>::writeIfDifferent(newValue, versionNumber);
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  ArrayAccessor<UserType>::ArrayAccessor(Module* owner, const std::string& name, VariableDirection direction,
+      std::string unit, size_t nElements, UpdateMode mode, const std::string& description,
+      const std::unordered_set<std::string>& tags)
+  : InversionOfControlAccessor<ArrayAccessor<UserType>>(
+        owner, name, direction, unit, nElements, mode, description, &typeid(UserType), tags) {}
+
+  /********************************************************************************************************************/
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  ArrayPushInput<UserType>::ArrayPushInput(Module* owner, const std::string& name, std::string unit, size_t nElements,
+      const std::string& description, const std::unordered_set<std::string>& tags)
+  : ArrayAccessor<UserType>(
+        owner, name, {VariableDirection::consuming, false}, unit, nElements, UpdateMode::push, description, tags) {}
+
+  /********************************************************************************************************************/
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  ArrayPollInput<UserType>::ArrayPollInput(Module* owner, const std::string& name, std::string unit, size_t nElements,
+      const std::string& description, const std::unordered_set<std::string>& tags)
+  : ArrayAccessor<UserType>(
+        owner, name, {VariableDirection::consuming, false}, unit, nElements, UpdateMode::poll, description, tags) {}
+
+  /********************************************************************************************************************/
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  ArrayOutput<UserType>::ArrayOutput(Module* owner, const std::string& name, std::string unit, size_t nElements,
+      const std::string& description, const std::unordered_set<std::string>& tags)
+  : ArrayAccessor<UserType>(
+        owner, name, {VariableDirection::feeding, false}, unit, nElements, UpdateMode::push, description, tags) {}
+
+  /********************************************************************************************************************/
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  ArrayPushInputWB<UserType>::ArrayPushInputWB(Module* owner, const std::string& name, std::string unit,
+      size_t nElements, const std::string& description, const std::unordered_set<std::string>& tags)
+  : ArrayAccessor<UserType>(
+        owner, name, {VariableDirection::consuming, true}, unit, nElements, UpdateMode::push, description, tags) {}
+
+  /********************************************************************************************************************/
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  ArrayOutputRB<UserType>::ArrayOutputRB(Module* owner, const std::string& name, std::string unit, size_t nElements,
+      const std::string& description, const std::unordered_set<std::string>& tags)
+  : ArrayAccessor<UserType>(
+        owner, name, {VariableDirection::feeding, true}, unit, nElements, UpdateMode::push, description, tags) {}
+
+  /********************************************************************************************************************/
+  /********************************************************************************************************************/
 
 } /* namespace ChimeraTK */
diff --git a/include/ConstantAccessor.h b/include/ConstantAccessor.h
index 24086d41..045f1c7b 100644
--- a/include/ConstantAccessor.h
+++ b/include/ConstantAccessor.h
@@ -6,6 +6,8 @@
 
 namespace ChimeraTK {
 
+  /********************************************************************************************************************/
+
   /** Implementation of the NDRegisterAccessor which delivers always the same
    * value and ignors any write operations.
 
@@ -22,34 +24,11 @@ namespace ChimeraTK {
   template<typename UserType>
   class ConstantAccessor : public ChimeraTK::NDRegisterAccessor<UserType> {
    public:
-    ConstantAccessor(UserType value = 0, size_t length = 1, AccessModeFlags accessModeFlags = AccessModeFlags{})
-    : ChimeraTK::NDRegisterAccessor<UserType>("UnnamedConstantAccessor", accessModeFlags), _value(length, value) {
-      ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D.resize(1);
-      ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D[0] = _value;
-
-      if(TransferElement::_accessModeFlags.has(AccessMode::wait_for_new_data)) {
-        // This implementation does not have a data transport queue, hence _readQueue
-        // is not set up as a continuation. We directly make it a cppext::future_queue
-        TransferElement::_readQueue = cppext::future_queue<void>(3); // minimum required length is 2
-        // Push once into the queue for the initial value.
-        TransferElement::_readQueue.push();
-      }
-    }
+    ConstantAccessor(UserType value = 0, size_t length = 1, AccessModeFlags accessModeFlags = AccessModeFlags{});
 
     void doReadTransferSynchronously() override {}
 
-    void doPostRead(TransferType /*type*/, bool updateUserBuffer) override {
-      // - updateUserBuffer is false for further calls to readLatest with wait_for_new_data.
-      //   In this case the user buffer must not be touched.
-      // - updateUserBuffer is true for all calls without wait_for_new_data. The user buffer must
-      //   be overwritten.
-      if(updateUserBuffer) {
-        ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D[0] = _value;
-        // It is OK to generate the version number just here since the read transfer is empty anyway.
-        this->_versionNumber = {};
-        this->_dataValidity = DataValidity::ok; // the constant is always valid by definiton
-      }
-    }
+    void doPostRead(TransferType /*type*/, bool updateUserBuffer) override;
 
     bool doWriteTransfer(ChimeraTK::VersionNumber /*versionNumber*/ = {}) override { return false; }
 
@@ -73,4 +52,39 @@ namespace ChimeraTK {
     std::vector<UserType> _value;
   };
 
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  ConstantAccessor<UserType>::ConstantAccessor(UserType value, size_t length, AccessModeFlags accessModeFlags)
+  : ChimeraTK::NDRegisterAccessor<UserType>("UnnamedConstantAccessor", accessModeFlags), _value(length, value) {
+    ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D.resize(1);
+    ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D[0] = _value;
+
+    if(TransferElement::_accessModeFlags.has(AccessMode::wait_for_new_data)) {
+      // This implementation does not have a data transport queue, hence _readQueue
+      // is not set up as a continuation. We directly make it a cppext::future_queue
+      TransferElement::_readQueue = cppext::future_queue<void>(3); // minimum required length is 2
+      // Push once into the queue for the initial value.
+      TransferElement::_readQueue.push();
+    }
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  void ConstantAccessor<UserType>::doPostRead(TransferType /*type*/, bool updateUserBuffer) {
+    // - updateUserBuffer is false for further calls to readLatest with wait_for_new_data.
+    //   In this case the user buffer must not be touched.
+    // - updateUserBuffer is true for all calls without wait_for_new_data. The user buffer must
+    //   be overwritten.
+    if(updateUserBuffer) {
+      ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D[0] = _value;
+      // It is OK to generate the version number just here since the read transfer is empty anyway.
+      this->_versionNumber = {};
+      this->_dataValidity = DataValidity::ok; // the constant is always valid by definiton
+    }
+  }
+
+  /********************************************************************************************************************/
+
 } /* namespace ChimeraTK */
diff --git a/include/ConsumingFanOut.h b/include/ConsumingFanOut.h
index 0e9d4e2f..91c6f47c 100644
--- a/include/ConsumingFanOut.h
+++ b/include/ConsumingFanOut.h
@@ -8,6 +8,8 @@
 
 namespace ChimeraTK {
 
+  /********************************************************************************************************************/
+
   /** FanOut implementation which acts as a read-only (i.e. consuming)
    * NDRegisterAccessor. The values read through this accessor will be obtained
    * from the given feeding implementation and distributed to any number of
@@ -16,52 +18,70 @@ namespace ChimeraTK {
   class ConsumingFanOut : public FanOut<UserType>, public ChimeraTK::NDRegisterAccessorDecorator<UserType> {
    public:
     ConsumingFanOut(boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> feedingImpl,
-        ConsumerImplementationPairs<UserType> const& consumerImplementationPairs)
-    : FanOut<UserType>(feedingImpl), ChimeraTK::NDRegisterAccessorDecorator<UserType>(feedingImpl) {
-      assert(feedingImpl->isReadable());
+        ConsumerImplementationPairs<UserType> const& consumerImplementationPairs);
 
-      _lastReceivedValue.resize(buffer_2D[0].size());
+    void doPostRead(TransferType type, bool updateDataBuffer) override;
 
-      // Add the consuming accessors
-      for(auto el : consumerImplementationPairs) {
-        FanOut<UserType>::addSlave(el.first, el.second);
-      }
+    void interrupt() override;
+
+   protected:
+    using ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D;
+    std::vector<UserType> _lastReceivedValue;
+  };
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  ConsumingFanOut<UserType>::ConsumingFanOut(boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> feedingImpl,
+      ConsumerImplementationPairs<UserType> const& consumerImplementationPairs)
+  : FanOut<UserType>(feedingImpl), ChimeraTK::NDRegisterAccessorDecorator<UserType>(feedingImpl) {
+    assert(feedingImpl->isReadable());
+
+    _lastReceivedValue.resize(buffer_2D[0].size());
+
+    // Add the consuming accessors
+    for(auto el : consumerImplementationPairs) {
+      FanOut<UserType>::addSlave(el.first, el.second);
     }
+  }
 
-    void doPostRead(TransferType type, bool updateDataBuffer) override {
-      ChimeraTK::NDRegisterAccessorDecorator<UserType>::doPostRead(type, updateDataBuffer);
+  /********************************************************************************************************************/
 
-      if(updateDataBuffer) {
-        // We have to keep a copy to write into the slaves. There might
-        // be decorators arount this fanout which swap out buffer_2D, so it is
-        // not available any more for a second read witout updateDataBuffer (exception case).
-        _lastReceivedValue = buffer_2D[0];
-      }
+  template<typename UserType>
+  void ConsumingFanOut<UserType>::doPostRead(TransferType type, bool updateDataBuffer) {
+    ChimeraTK::NDRegisterAccessorDecorator<UserType>::doPostRead(type, updateDataBuffer);
 
-      // The ConsumingFanOut conceptually never has a wait_fow_new_data flags. Hence each read
-      // operation returns with "new" data, even in case of an exception. So each read
-      // always synchronises all slaves and pushes the content of the data buffer.
-      for(auto& slave : FanOut<UserType>::slaves) { // send out copies to slaves
-        // do not send copy if no data is expected (e.g. trigger)
-        if(slave->getNumberOfSamples() != 0) {
-          slave->accessChannel(0) = _lastReceivedValue;
-        }
-        slave->setDataValidity(this->dataValidity());
-        slave->writeDestructively();
-      }
+    if(updateDataBuffer) {
+      // We have to keep a copy to write into the slaves. There might
+      // be decorators arount this fanout which swap out buffer_2D, so it is
+      // not available any more for a second read witout updateDataBuffer (exception case).
+      _lastReceivedValue = buffer_2D[0];
     }
 
-    void interrupt() override {
-      // call the interrut sequences of the fan out (interrupts for fan input and all outputs), and the ndRegisterAccessor
-      FanOut<UserType>::interrupt();
-      if(this->_accessModeFlags.has(AccessMode::wait_for_new_data)) {
-        ChimeraTK::NDRegisterAccessor<UserType>::interrupt();
+    // The ConsumingFanOut conceptually never has a wait_fow_new_data flags. Hence each read
+    // operation returns with "new" data, even in case of an exception. So each read
+    // always synchronises all slaves and pushes the content of the data buffer.
+    for(auto& slave : FanOut<UserType>::slaves) { // send out copies to slaves
+      // do not send copy if no data is expected (e.g. trigger)
+      if(slave->getNumberOfSamples() != 0) {
+        slave->accessChannel(0) = _lastReceivedValue;
       }
+      slave->setDataValidity(this->dataValidity());
+      slave->writeDestructively();
     }
+  }
 
-   protected:
-    using ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D;
-    std::vector<UserType> _lastReceivedValue;
-  };
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  void ConsumingFanOut<UserType>::interrupt() {
+    // call the interrut sequences of the fan out (interrupts for fan input and all outputs), and the ndRegisterAccessor
+    FanOut<UserType>::interrupt();
+    if(this->_accessModeFlags.has(AccessMode::wait_for_new_data)) {
+      ChimeraTK::NDRegisterAccessor<UserType>::interrupt();
+    }
+  }
+
+  /********************************************************************************************************************/
 
 } /* namespace ChimeraTK */
diff --git a/include/ControlSystemModule.h b/include/ControlSystemModule.h
index cecb9159..f9c85e4c 100644
--- a/include/ControlSystemModule.h
+++ b/include/ControlSystemModule.h
@@ -20,12 +20,7 @@ namespace ChimeraTK {
     ControlSystemModule(ControlSystemModule&& other) { operator=(std::move(other)); }
 
     /** Move assignment */
-    ControlSystemModule& operator=(ControlSystemModule&& other) {
-      Module::operator=(std::move(other));
-      variableNamePrefix = std::move(other.variableNamePrefix);
-      subModules = std::move(other.subModules);
-      return *this;
-    }
+    ControlSystemModule& operator=(ControlSystemModule&& other);
 
     /** The function call operator returns a VariableNetworkNode which can be used
      * in the Application::initialise() function to connect the control system
diff --git a/include/DebugPrintAccessorDecorator.h b/include/DebugPrintAccessorDecorator.h
index 51b54a48..8b810242 100644
--- a/include/DebugPrintAccessorDecorator.h
+++ b/include/DebugPrintAccessorDecorator.h
@@ -8,64 +8,38 @@
 
 namespace ChimeraTK {
 
-  /** Decorator of the NDRegisterAccessor which facilitates tests of the
-   * application */
+  /********************************************************************************************************************/
+
+  /**
+   * Decorator of the NDRegisterAccessor which facilitates tests of the application
+   */
   template<typename UserType>
   class DebugPrintAccessorDecorator : public ChimeraTK::NDRegisterAccessorDecorator<UserType> {
    public:
     DebugPrintAccessorDecorator(
-        boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> accessor, const std::string& fullyQualifiedName)
-    : ChimeraTK::NDRegisterAccessorDecorator<UserType>(accessor), _fullyQualifiedName(fullyQualifiedName) {
-      std::cout << "Enable debug output for variable '" << _fullyQualifiedName << "'." << std::endl;
-    }
-
-    bool doWriteTransfer(ChimeraTK::VersionNumber versionNumber) override {
-      std::cout << "doWriteTransfer() called on '" << _fullyQualifiedName << "'." << std::flush;
-      auto ret = ChimeraTK::NDRegisterAccessorDecorator<UserType>::doWriteTransfer(versionNumber);
-      if(ret) {
-        std::cout << " -> DATA LOSS!";
-      }
-      std::cout << std::endl;
-      return ret;
-    }
-
-    bool doWriteTransferDestructively(ChimeraTK::VersionNumber versionNumber) override {
-      std::cout << "doWriteTransferDestructively() called on '" << _fullyQualifiedName << "'." << std::flush;
-      auto ret = ChimeraTK::NDRegisterAccessorDecorator<UserType>::doWriteTransferDestructively(versionNumber);
-      if(ret) {
-        std::cout << " -> DATA LOSS!";
-      }
-      std::cout << std::endl;
-      return ret;
-    }
-
-    void doReadTransferSynchronously() override {
-      std::cout << "doReadTransferSynchronously() called on '" << _fullyQualifiedName << "'." << std::endl;
-      ChimeraTK::NDRegisterAccessorDecorator<UserType>::doReadTransferSynchronously();
-    }
-
-    void doPreRead(TransferType type) override {
-      std::cout << "preRead() called on '" << _fullyQualifiedName << "'." << std::endl;
-      ChimeraTK::NDRegisterAccessorDecorator<UserType>::doPreRead(type);
-    }
-
-    void doPostRead(TransferType type, bool hasNewData) override {
-      std::cout << "postRead() called on '" << _fullyQualifiedName << "'." << std::endl;
-      ChimeraTK::NDRegisterAccessorDecorator<UserType>::doPostRead(type, hasNewData);
-    }
-
-    void doPreWrite(TransferType type, VersionNumber versionNumber) override {
-      std::cout << "preWrite() called on '" << _fullyQualifiedName << "'." << std::endl;
-      ChimeraTK::NDRegisterAccessorDecorator<UserType>::doPreWrite(type, versionNumber);
-    }
-
-    void doPostWrite(TransferType type, VersionNumber versionNumber) override {
-      std::cout << "postWrite() called on '" << _fullyQualifiedName << "'." << std::endl;
-      ChimeraTK::NDRegisterAccessorDecorator<UserType>::doPostWrite(type, versionNumber);
-    }
+        boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> accessor, const std::string& fullyQualifiedName);
+
+    bool doWriteTransfer(ChimeraTK::VersionNumber versionNumber) override;
+
+    bool doWriteTransferDestructively(ChimeraTK::VersionNumber versionNumber) override;
+
+    void doReadTransferSynchronously() override;
+
+    void doPreRead(TransferType type) override;
+
+    void doPostRead(TransferType type, bool hasNewData) override;
+
+    void doPreWrite(TransferType type, VersionNumber versionNumber) override;
+
+    void doPostWrite(TransferType type, VersionNumber versionNumber) override;
 
    protected:
     std::string _fullyQualifiedName;
   };
 
+  /********************************************************************************************************************/
+
+  DECLARE_TEMPLATE_FOR_CHIMERATK_USER_TYPES(DebugPrintAccessorDecorator);
+
+  /********************************************************************************************************************/
 } /* namespace ChimeraTK */
diff --git a/include/DeviceModule.h b/include/DeviceModule.h
index 1a24bdb6..ab7d526e 100644
--- a/include/DeviceModule.h
+++ b/include/DeviceModule.h
@@ -31,18 +31,24 @@ namespace ChimeraTK {
   namespace detail {
     struct DeviceModuleProxy : Module {
       DeviceModuleProxy(const DeviceModule& owner, const std::string& registerNamePrefix);
+
       DeviceModuleProxy(DeviceModuleProxy&& other);
-      DeviceModuleProxy() {}
+
+      DeviceModuleProxy() = default;
 
       VariableNetworkNode operator()(const std::string& registerName, UpdateMode mode,
           const std::type_info& valueType = typeid(AnyType), size_t nElements = 0) const;
+
       VariableNetworkNode operator()(const std::string& registerName, const std::type_info& valueType,
           size_t nElements = 0, UpdateMode mode = UpdateMode::poll) const;
+
       VariableNetworkNode operator()(const std::string& variableName) const override;
       Module& operator[](const std::string& moduleName) const override;
 
       const Module& virtualise() const override;
+
       void connectTo(const Module& target, VariableNetworkNode trigger = {}) const override;
+
       ModuleType getModuleType() const override { return ModuleType::Device; }
 
       DeviceModuleProxy& operator=(DeviceModuleProxy&& other);
@@ -82,34 +88,18 @@ namespace ChimeraTK {
     DeviceModule(DeviceModule&& other) { operator=(std::move(other)); }
 
     /** Move assignment */
-    DeviceModule& operator=(DeviceModule&& other) {
-      assert(!moduleThread.joinable());
-      assert(other.isHoldingInitialValueLatch);
-      if(owner) owner->unregisterDeviceModule(this);
-      Module::operator=(std::move(other));
-      device = std::move(other.device);
-      deviceAliasOrURI = std::move(other.deviceAliasOrURI);
-      registerNamePrefix = std::move(other.registerNamePrefix);
-      deviceError = std::move(other.deviceError);
-      owner = other.owner;
-      proxies = std::move(other.proxies);
-      deviceHasError = other.deviceHasError;
-      for(auto& proxy : proxies) proxy.second._myowner = this;
-      owner->registerDeviceModule(this);
-      return *this;
-    }
+    DeviceModule& operator=(DeviceModule&& other);
+
     /** The subscript operator returns a VariableNetworkNode which can be used in
      * the Application::initialise()
      *  function to connect the register with another variable. */
     VariableNetworkNode operator()(const std::string& registerName, UpdateMode mode,
         const std::type_info& valueType = typeid(AnyType), size_t nElements = 0) const;
+
     VariableNetworkNode operator()(const std::string& registerName, const std::type_info& valueType,
-        size_t nElements = 0, UpdateMode mode = UpdateMode::poll) const {
-      return operator()(registerName, mode, valueType, nElements);
-    }
-    VariableNetworkNode operator()(const std::string& variableName) const override {
-      return operator()(variableName, UpdateMode::poll);
-    }
+        size_t nElements = 0, UpdateMode mode = UpdateMode::poll) const;
+
+    VariableNetworkNode operator()(const std::string& variableName) const override;
 
     Module& operator[](const std::string& moduleName) const override;
 
@@ -133,9 +123,7 @@ namespace ChimeraTK {
 
     VersionNumber getCurrentVersionNumber() const override { return currentVersionNumber; }
 
-    void setCurrentVersionNumber(VersionNumber versionNumber) override {
-      if(versionNumber > currentVersionNumber) currentVersionNumber = versionNumber;
-    }
+    void setCurrentVersionNumber(VersionNumber versionNumber) override;
 
     VersionNumber currentVersionNumber{nullptr};
 
@@ -145,14 +133,10 @@ namespace ChimeraTK {
     mutable Device device;
 
     DataValidity getDataValidity() const override { return DataValidity::ok; }
-    void incrementDataFaultCounter() override {
-      throw ChimeraTK::logic_error("incrementDataFaultCounter() called on a DeviceModule. This is probably "
-                                   "caused by incorrect ownership of variables/accessors or VariableGroups.");
-    }
-    void decrementDataFaultCounter() override {
-      throw ChimeraTK::logic_error("decrementDataFaultCounter() called on a DeviceModule. This is probably "
-                                   "caused by incorrect ownership of variables/accessors or VariableGroups.");
-    }
+
+    void incrementDataFaultCounter() override;
+
+    void decrementDataFaultCounter() override;
 
     /** Add initialisation handlers to the device.
      *
diff --git a/include/EntityOwner.h b/include/EntityOwner.h
index 50a0f2a1..360b1819 100644
--- a/include/EntityOwner.h
+++ b/include/EntityOwner.h
@@ -10,16 +10,22 @@
 
 namespace ChimeraTK {
 
+  /********************************************************************************************************************/
+
   class AccessorBase;
   class Module;
   class VirtualModule;
 
+  /********************************************************************************************************************/
+
   /**
    *  Convenience type definition which can optionally be used as a shortcut for the type which defines a list of
    *  tags.
    */
   using TAGS = const std::unordered_set<std::string>;
 
+  /********************************************************************************************************************/
+
   /**
    *  Base class for owners of other EntityOwners (e.g. Modules) and Accessors.
    *  FIXME: Unify with Module class (not straight forward!).
@@ -38,9 +44,7 @@ namespace ChimeraTK {
         const std::unordered_set<std::string>& tags = {});
 
     /** Default constructor just for late initialisation */
-    EntityOwner()
-    : _name("**INVALID**"), _description("Invalid EntityOwner created by default constructor just "
-                                         "as a place holder") {}
+    EntityOwner();
 
     /** Virtual destructor to make the type polymorphic */
     virtual ~EntityOwner();
@@ -106,10 +110,7 @@ namespace ChimeraTK {
 
     /** Called inside the constructor of Accessor: adds the accessor to the list
      */
-    void registerAccessor(VariableNetworkNode accessor) {
-      for(auto& tag : _tags) accessor.addTag(tag);
-      accessorList.push_back(accessor);
-    }
+    void registerAccessor(VariableNetworkNode accessor);
 
     /** Called inside the destructor of Accessor: removes the accessor from the
      * list */
@@ -272,4 +273,6 @@ namespace ChimeraTK {
     return "@CONST@" + userTypeToUserType<std::string>(value);
   }
 
+  /********************************************************************************************************************/
+
 } /* namespace ChimeraTK */
diff --git a/include/FanOut.h b/include/FanOut.h
index a86fdeb1..82ea8d63 100644
--- a/include/FanOut.h
+++ b/include/FanOut.h
@@ -11,10 +11,14 @@
 
 namespace ChimeraTK {
 
+  /********************************************************************************************************************/
+
   template<typename UserType>
   using ConsumerImplementationPairs =
       std::list<std::pair<boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>>, VariableNetworkNode>>;
 
+  /********************************************************************************************************************/
+
   /** Type independent base */
   class FanOutBase {
    public:
@@ -30,6 +34,8 @@ namespace ChimeraTK {
     bool _disabled{false};
   };
 
+  /********************************************************************************************************************/
+
   /** Base class for several implementations which distribute values from one
    * feeder to multiple consumers */
   template<typename UserType>
@@ -40,59 +46,13 @@ namespace ChimeraTK {
     /** Add a slave to the FanOut. Only sending end-points of a consuming node may
      * be added. */
     virtual void addSlave(
-        boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> slave, VariableNetworkNode& /*consumer*/) {
-      if(!slave->isWriteable()) {
-        throw ChimeraTK::logic_error("FanOut::addSlave() has been called with a "
-                                     "receiving implementation!");
-      }
-      // check if array shape is compatible, unless the receiver is a trigger
-      // node, so no data is expected
-      if(slave->getNumberOfSamples() != 0 &&
-          (slave->getNumberOfChannels() != impl->getNumberOfChannels() ||
-              slave->getNumberOfSamples() != impl->getNumberOfSamples())) {
-        std::string what = "FanOut::addSlave(): Trying to add a slave '";
-        what += slave->getName();
-        what += "' with incompatible array shape! Name of master: ";
-        what += impl->getName();
-        what += " Length of master: " + std::to_string(impl->getNumberOfChannels()) + " x " +
-            std::to_string(impl->getNumberOfSamples());
-        what += " Length of slave: " + std::to_string(slave->getNumberOfChannels()) + " x " +
-            std::to_string(slave->getNumberOfSamples());
-        throw ChimeraTK::logic_error(what.c_str());
-      }
-      slaves.push_back(slave);
-    }
+        boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> slave, VariableNetworkNode& /*consumer*/);
 
     // remove a slave identified by its consuming node from the FanOut
-    void removeSlave(const boost::shared_ptr<ChimeraTK::TransferElement>& slave) override {
-      // make sure the slave is actually currently in the list, and get it by the right typ
-      boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> slave_typed;
-      for(auto& s : slaves) {
-        if(s == slave) {
-          slave_typed = s;
-          break;
-        }
-      }
-      assert(slave_typed != nullptr);
-
-      size_t nOld = slaves.size();
-      slaves.remove(slave_typed);
-      assert(slaves.size() == nOld - 1);
-    }
+    void removeSlave(const boost::shared_ptr<ChimeraTK::TransferElement>& slave) override;
 
     // interrupt the input and all slaves
-    virtual void interrupt() {
-      if(impl) {
-        if(impl->getAccessModeFlags().has(AccessMode::wait_for_new_data)) {
-          impl->interrupt();
-        }
-      }
-      for(auto& slave : slaves) {
-        if(slave->getAccessModeFlags().has(AccessMode::wait_for_new_data)) {
-          slave->interrupt();
-        }
-      }
-    }
+    virtual void interrupt();
 
    protected:
     boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> impl;
@@ -100,4 +60,69 @@ namespace ChimeraTK {
     std::list<boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>>> slaves;
   };
 
+  /********************************************************************************************************************/
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  void FanOut<UserType>::addSlave(
+      boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> slave, VariableNetworkNode& /*consumer*/) {
+    if(!slave->isWriteable()) {
+      throw ChimeraTK::logic_error("FanOut::addSlave() has been called with a "
+                                   "receiving implementation!");
+    }
+    // check if array shape is compatible, unless the receiver is a trigger
+    // node, so no data is expected
+    if(slave->getNumberOfSamples() != 0 &&
+        (slave->getNumberOfChannels() != impl->getNumberOfChannels() ||
+            slave->getNumberOfSamples() != impl->getNumberOfSamples())) {
+      std::string what = "FanOut::addSlave(): Trying to add a slave '";
+      what += slave->getName();
+      what += "' with incompatible array shape! Name of master: ";
+      what += impl->getName();
+      what += " Length of master: " + std::to_string(impl->getNumberOfChannels()) + " x " +
+          std::to_string(impl->getNumberOfSamples());
+      what += " Length of slave: " + std::to_string(slave->getNumberOfChannels()) + " x " +
+          std::to_string(slave->getNumberOfSamples());
+      throw ChimeraTK::logic_error(what.c_str());
+    }
+    slaves.push_back(slave);
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  void FanOut<UserType>::removeSlave(const boost::shared_ptr<ChimeraTK::TransferElement>& slave) {
+    // make sure the slave is actually currently in the list, and get it by the right typ
+    boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> slave_typed;
+    for(auto& s : slaves) {
+      if(s == slave) {
+        slave_typed = s;
+        break;
+      }
+    }
+    assert(slave_typed != nullptr);
+
+    size_t nOld = slaves.size();
+    slaves.remove(slave_typed);
+    assert(slaves.size() == nOld - 1);
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  void FanOut<UserType>::interrupt() {
+    if(impl) {
+      if(impl->getAccessModeFlags().has(AccessMode::wait_for_new_data)) {
+        impl->interrupt();
+      }
+    }
+    for(auto& slave : slaves) {
+      if(slave->getAccessModeFlags().has(AccessMode::wait_for_new_data)) {
+        slave->interrupt();
+      }
+    }
+  }
+
+  /********************************************************************************************************************/
+
 } /* namespace ChimeraTK */
diff --git a/include/FeedingFanOut.h b/include/FeedingFanOut.h
index 696de4a6..000b86a5 100644
--- a/include/FeedingFanOut.h
+++ b/include/FeedingFanOut.h
@@ -11,6 +11,8 @@
 
 namespace ChimeraTK {
 
+  /********************************************************************************************************************/
+
   /**
    * NDRegisterAccessor implementation which distributes values written to this
    * accessor out to any number of slaves.
@@ -20,208 +22,284 @@ namespace ChimeraTK {
    public:
     FeedingFanOut(std::string const& name, std::string const& unit, std::string const& description,
         size_t numberOfElements, bool withReturn,
-        ConsumerImplementationPairs<UserType> const& consumerImplementationPairs)
-    : FanOut<UserType>(boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>>()),
-      // We pass default-constructed, empty AccessModeFlags, they may later be determined from _returnSlave
-      ChimeraTK::NDRegisterAccessor<UserType>("FeedingFanOut:" + name, AccessModeFlags{}, unit, description),
-      _withReturn(withReturn) {
-      ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D.resize(1);
-      ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D[0].resize(numberOfElements);
-
-      this->_readQueue = cppext::future_queue<void>(3);
-
-      // Add the consuming accessors
-      // TODO FanOut constructors and addSlave should get refactoring
-      for(auto el : consumerImplementationPairs) {
-        addSlave(el.first, el.second);
-      }
-    }
+        ConsumerImplementationPairs<UserType> const& consumerImplementationPairs);
 
     /** Add a slave to the FanOut. Only sending end-points of a consuming node may
      * be added. */
-    void addSlave(boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> slave, VariableNetworkNode&) override {
-      // check if array shape is compatible, unless the receiver is a trigger
-      // node, so no data is expected
-      if(slave->getNumberOfSamples() != 0 &&
-          (slave->getNumberOfChannels() != 1 || slave->getNumberOfSamples() != this->getNumberOfSamples())) {
-        std::string what = "FeedingFanOut::addSlave(): Trying to add a slave '" + slave->getName();
-        what += "' with incompatible array shape! Name of fan out: '" + this->getName() + "'";
-        throw ChimeraTK::logic_error(what.c_str());
-      }
+    void addSlave(boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> slave, VariableNetworkNode&) override;
 
-      // make sure slave is writeable
-      if(!slave->isWriteable()) {
-        throw ChimeraTK::logic_error("FeedingFanOut::addSlave() has been called "
-                                     "with a receiving implementation!");
-      }
+    bool isReadable() const override { return _withReturn; }
 
-      // handle return channels
-      if(_withReturn) {
-        if(slave->isReadable()) {
-          if(_hasReturnSlave) {
-            throw ChimeraTK::logic_error("FeedingFanOut: Cannot add multiple slaves with return channel!");
-          }
+    bool isReadOnly() const override { return false; }
 
-          // Assert the assumption about the return channel made in the constructor
-          assert(slave->getAccessModeFlags().has(AccessMode::wait_for_new_data));
+    bool isWriteable() const override { return true; }
 
-          _hasReturnSlave = true;
-          _returnSlave = slave;
+    void doReadTransferSynchronously() override;
 
-          // Set the readQeue from the return slave
-          // As this becomes the implemention of the feeding output, the flags are determined by that slave accessor
-          // If not _withReturn, the queue is not relevant because the feeding node is on output which is never read
-          this->_readQueue = _returnSlave->getReadQueue();
-          this->_accessModeFlags = _returnSlave->getAccessModeFlags();
-        }
-      }
+    void doPreRead(TransferType type) override;
 
-      // add the slave
-      FanOut<UserType>::slaves.push_back(slave);
-    }
+    void doPostRead(TransferType type, bool hasNewData) override;
 
-    bool isReadable() const override { return _withReturn; }
+    void doPreWrite(TransferType, VersionNumber) override;
 
-    bool isReadOnly() const override { return false; }
+    bool doWriteTransfer(ChimeraTK::VersionNumber versionNumber) override;
 
-    bool isWriteable() const override { return true; }
+    bool doWriteTransferDestructively(ChimeraTK::VersionNumber versionNumber = {}) override;
+
+    void doPostWrite(TransferType, VersionNumber) override;
+
+    bool mayReplaceOther(const boost::shared_ptr<const ChimeraTK::TransferElement>&) const override;
+
+    std::list<boost::shared_ptr<ChimeraTK::TransferElement>> getInternalElements() override;
+
+    std::vector<boost::shared_ptr<ChimeraTK::TransferElement>> getHardwareAccessingElements() override;
+
+    void replaceTransferElement(boost::shared_ptr<ChimeraTK::TransferElement>) override;
 
-    void doReadTransferSynchronously() override {
-      if(this->_disabled) return;
-      assert(_withReturn);
-      _returnSlave->readTransfer();
+    boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> getReturnSlave() { return _returnSlave; }
+
+    void interrupt() override;
+
+   protected:
+    /// Flag whether this FeedingFanOut has a return channel. Is specified in the
+    /// constructor
+    bool _withReturn;
+
+    /// Used if _withReturn is true: flag whether the corresponding slave with the
+    /// return channel has already been added.
+    bool _hasReturnSlave{false};
+
+    /// The slave with return channel
+    boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> _returnSlave;
+
+    /// DataValidity to attach to the data
+    DataValidity validity{DataValidity::ok};
+  };
+
+  /********************************************************************************************************************/
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  FeedingFanOut<UserType>::FeedingFanOut(std::string const& name, std::string const& unit,
+      std::string const& description, size_t numberOfElements, bool withReturn,
+      ConsumerImplementationPairs<UserType> const& consumerImplementationPairs)
+  : FanOut<UserType>(boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>>()),
+    // We pass default-constructed, empty AccessModeFlags, they may later be determined from _returnSlave
+    ChimeraTK::NDRegisterAccessor<UserType>("FeedingFanOut:" + name, AccessModeFlags{}, unit, description),
+    _withReturn(withReturn) {
+    ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D.resize(1);
+    ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D[0].resize(numberOfElements);
+
+    this->_readQueue = cppext::future_queue<void>(3);
+
+    // Add the consuming accessors
+    // TODO FanOut constructors and addSlave should get refactoring
+    for(auto el : consumerImplementationPairs) {
+      addSlave(el.first, el.second);
     }
+  }
 
-    void doPreRead(TransferType type) override {
-      if(!_withReturn) throw ChimeraTK::logic_error("Read operation called on write-only variable.");
-      if(this->_disabled) return;
-      _returnSlave->accessChannel(0).swap(ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D[0]);
-      _returnSlave->preRead(type);
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  void FeedingFanOut<UserType>::addSlave(
+      boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> slave, VariableNetworkNode&) {
+    // check if array shape is compatible, unless the receiver is a trigger
+    // node, so no data is expected
+    if(slave->getNumberOfSamples() != 0 &&
+        (slave->getNumberOfChannels() != 1 || slave->getNumberOfSamples() != this->getNumberOfSamples())) {
+      std::string what = "FeedingFanOut::addSlave(): Trying to add a slave '" + slave->getName();
+      what += "' with incompatible array shape! Name of fan out: '" + this->getName() + "'";
+      throw ChimeraTK::logic_error(what.c_str());
     }
 
-    void doPostRead(TransferType type, bool hasNewData) override {
-      if(this->_disabled) return;
-      assert(_withReturn);
-      assert(_hasReturnSlave);
-
-      auto _ = cppext::finally([&] {
-        if(!hasNewData) return;
-        _returnSlave->accessChannel(0).swap(ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D[0]);
-        // distribute return-channel update to the other slaves
-        for(auto& slave : FanOut<UserType>::slaves) { // send out copies to slaves
-          if(slave == _returnSlave) continue;
-          if(slave->getNumberOfSamples() != 0) { // do not send copy if no data is expected (e.g. trigger)
-            slave->accessChannel(0) = ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D[0];
-          }
-          slave->writeDestructively(_returnSlave->getVersionNumber());
+    // make sure slave is writeable
+    if(!slave->isWriteable()) {
+      throw ChimeraTK::logic_error("FeedingFanOut::addSlave() has been called "
+                                   "with a receiving implementation!");
+    }
+
+    // handle return channels
+    if(_withReturn) {
+      if(slave->isReadable()) {
+        if(_hasReturnSlave) {
+          throw ChimeraTK::logic_error("FeedingFanOut: Cannot add multiple slaves with return channel!");
         }
-      });
 
-      _returnSlave->postRead(type, hasNewData);
+        // Assert the assumption about the return channel made in the constructor
+        assert(slave->getAccessModeFlags().has(AccessMode::wait_for_new_data));
+
+        _hasReturnSlave = true;
+        _returnSlave = slave;
 
-      this->_versionNumber = _returnSlave->getVersionNumber();
-      this->_dataValidity = _returnSlave->dataValidity();
+        // Set the readQeue from the return slave
+        // As this becomes the implemention of the feeding output, the flags are determined by that slave accessor
+        // If not _withReturn, the queue is not relevant because the feeding node is on output which is never read
+        this->_readQueue = _returnSlave->getReadQueue();
+        this->_accessModeFlags = _returnSlave->getAccessModeFlags();
+      }
     }
 
-    void doPreWrite(TransferType, VersionNumber) override {
-      if(this->_disabled) return;
-      for(auto& slave : FanOut<UserType>::slaves) {       // send out copies to slaves
-        if(slave->getNumberOfSamples() != 0) {            // do not send copy if no data is expected (e.g. trigger)
-          if(slave == FanOut<UserType>::slaves.front()) { // in case of first slave, swap instead of copy
-            slave->accessChannel(0).swap(ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D[0]);
-          }
-          else { // not the first slave: copy the data from the first slave
-            slave->accessChannel(0) = FanOut<UserType>::slaves.front()->accessChannel(0);
-          }
+    // add the slave
+    FanOut<UserType>::slaves.push_back(slave);
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  void FeedingFanOut<UserType>::doReadTransferSynchronously() {
+    if(this->_disabled) return;
+    assert(_withReturn);
+    _returnSlave->readTransfer();
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  void FeedingFanOut<UserType>::doPreRead(TransferType type) {
+    if(!_withReturn) throw ChimeraTK::logic_error("Read operation called on write-only variable.");
+    if(this->_disabled) return;
+    _returnSlave->accessChannel(0).swap(ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D[0]);
+    _returnSlave->preRead(type);
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  void FeedingFanOut<UserType>::doPostRead(TransferType type, bool hasNewData) {
+    if(this->_disabled) return;
+    assert(_withReturn);
+    assert(_hasReturnSlave);
+
+    auto _ = cppext::finally([&] {
+      if(!hasNewData) return;
+      _returnSlave->accessChannel(0).swap(ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D[0]);
+      // distribute return-channel update to the other slaves
+      for(auto& slave : FanOut<UserType>::slaves) { // send out copies to slaves
+        if(slave == _returnSlave) continue;
+        if(slave->getNumberOfSamples() != 0) { // do not send copy if no data is expected (e.g. trigger)
+          slave->accessChannel(0) = ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D[0];
         }
-        slave->setDataValidity(this->dataValidity());
+        slave->writeDestructively(_returnSlave->getVersionNumber());
       }
+    });
 
-      // Don't call pre-write on the slaves. Each slave has to do it's own exception handling, so we call the whole
-      // operation in doWriteTansfer(). To fulfill the TransferElement specification we would have to check the
-      // pre-conditions here so no logic error is thrown in the transfer phase (logic_errors are predictable and can
-      // always pre prevented. They should be thrown here already).
-      // FIXME: At the moment we can be lazy about it. logic_errors are not treated in ApplicationCore and the only
-      // effect is that the logic_error would be delayed after postRead() and terminate the application there, and not
-      // after the transfer. Advantage about being lazy: It safes a few virtual function calls.
-    }
+    _returnSlave->postRead(type, hasNewData);
+
+    this->_versionNumber = _returnSlave->getVersionNumber();
+    this->_dataValidity = _returnSlave->dataValidity();
+  }
+
+  /********************************************************************************************************************/
 
-    bool doWriteTransfer(ChimeraTK::VersionNumber versionNumber) override {
-      if(this->_disabled) return false;
-      bool dataLost = false;
-      bool isFirst = true;
-      for(auto& slave : FanOut<UserType>::slaves) {
-        bool ret;
-        if(isFirst) {
-          isFirst = false;
-          ret = slave->write(versionNumber);
+  template<typename UserType>
+  void FeedingFanOut<UserType>::doPreWrite(TransferType, VersionNumber) {
+    if(this->_disabled) return;
+    for(auto& slave : FanOut<UserType>::slaves) {       // send out copies to slaves
+      if(slave->getNumberOfSamples() != 0) {            // do not send copy if no data is expected (e.g. trigger)
+        if(slave == FanOut<UserType>::slaves.front()) { // in case of first slave, swap instead of copy
+          slave->accessChannel(0).swap(ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D[0]);
         }
-        else {
-          ret = slave->writeDestructively(versionNumber);
+        else { // not the first slave: copy the data from the first slave
+          slave->accessChannel(0) = FanOut<UserType>::slaves.front()->accessChannel(0);
         }
-        if(ret) dataLost = true;
       }
-      return dataLost;
+      slave->setDataValidity(this->dataValidity());
     }
 
-    bool doWriteTransferDestructively(ChimeraTK::VersionNumber versionNumber = {}) override {
-      if(this->_disabled) return false;
-      bool dataLost = false;
-      for(auto& slave : FanOut<UserType>::slaves) {
-        bool ret = slave->writeDestructively(versionNumber);
-        if(ret) dataLost = true;
+    // Don't call pre-write on the slaves. Each slave has to do it's own exception handling, so we call the whole
+    // operation in doWriteTansfer(). To fulfill the TransferElement specification we would have to check the
+    // pre-conditions here so no logic error is thrown in the transfer phase (logic_errors are predictable and can
+    // always pre prevented. They should be thrown here already).
+    // FIXME: At the moment we can be lazy about it. logic_errors are not treated in ApplicationCore and the only
+    // effect is that the logic_error would be delayed after postRead() and terminate the application there, and not
+    // after the transfer. Advantage about being lazy: It safes a few virtual function calls.
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  bool FeedingFanOut<UserType>::doWriteTransfer(ChimeraTK::VersionNumber versionNumber) {
+    if(this->_disabled) return false;
+    bool dataLost = false;
+    bool isFirst = true;
+    for(auto& slave : FanOut<UserType>::slaves) {
+      bool ret;
+      if(isFirst) {
+        isFirst = false;
+        ret = slave->write(versionNumber);
+      }
+      else {
+        ret = slave->writeDestructively(versionNumber);
       }
-      return dataLost;
+      if(ret) dataLost = true;
     }
+    return dataLost;
+  }
 
-    void doPostWrite(TransferType, VersionNumber) override {
-      if(this->_disabled) return;
-      // the postWrite() on the slaves has already been called
-      FanOut<UserType>::slaves.front()->accessChannel(0).swap(ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D[0]);
-    }
+  /********************************************************************************************************************/
 
-    bool mayReplaceOther(const boost::shared_ptr<const ChimeraTK::TransferElement>&) const override {
-      return false; /// @todo implement properly?
+  template<typename UserType>
+  bool FeedingFanOut<UserType>::doWriteTransferDestructively(ChimeraTK::VersionNumber versionNumber) {
+    if(this->_disabled) return false;
+    bool dataLost = false;
+    for(auto& slave : FanOut<UserType>::slaves) {
+      bool ret = slave->writeDestructively(versionNumber);
+      if(ret) dataLost = true;
     }
+    return dataLost;
+  }
 
-    std::list<boost::shared_ptr<ChimeraTK::TransferElement>> getInternalElements() override {
-      return {}; /// @todo implement properly?
-    }
+  /********************************************************************************************************************/
 
-    std::vector<boost::shared_ptr<ChimeraTK::TransferElement>> getHardwareAccessingElements() override {
-      return {boost::enable_shared_from_this<ChimeraTK::TransferElement>::shared_from_this()}; /// @todo implement
-                                                                                               /// properly?
-    }
+  template<typename UserType>
+  void FeedingFanOut<UserType>::doPostWrite(TransferType, VersionNumber) {
+    if(this->_disabled) return;
+    // the postWrite() on the slaves has already been called
+    FanOut<UserType>::slaves.front()->accessChannel(0).swap(ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D[0]);
+  }
 
-    void replaceTransferElement(boost::shared_ptr<ChimeraTK::TransferElement>) override {
-      // You can't replace anything here. Just do nothing.
-      /// @todo implement properly?
-    }
+  /********************************************************************************************************************/
 
-    boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> getReturnSlave() { return _returnSlave; }
+  template<typename UserType>
+  bool FeedingFanOut<UserType>::mayReplaceOther(const boost::shared_ptr<const ChimeraTK::TransferElement>&) const {
+    return false; /// @todo implement properly?
+  }
 
-    void interrupt() override {
-      // call the interrut sequences of the fan out (interrupts for fan input and all outputs), and the ndRegisterAccessor
-      FanOut<UserType>::interrupt();
-      if(_withReturn) {
-        _returnSlave->interrupt();
-      }
-    }
+  /********************************************************************************************************************/
 
-   protected:
-    /// Flag whether this FeedingFanOut has a return channel. Is specified in the
-    /// constructor
-    bool _withReturn;
+  template<typename UserType>
+  std::list<boost::shared_ptr<ChimeraTK::TransferElement>> FeedingFanOut<UserType>::getInternalElements() {
+    return {}; /// @todo implement properly?
+  }
 
-    /// Used if _withReturn is true: flag whether the corresponding slave with the
-    /// return channel has already been added.
-    bool _hasReturnSlave{false};
+  /********************************************************************************************************************/
 
-    /// The slave with return channel
-    boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> _returnSlave;
+  template<typename UserType>
+  std::vector<boost::shared_ptr<ChimeraTK::TransferElement>> FeedingFanOut<UserType>::getHardwareAccessingElements() {
+    return {boost::enable_shared_from_this<ChimeraTK::TransferElement>::shared_from_this()}; /// @todo implement
+                                                                                             /// properly?
+  }
 
-    /// DataValidity to attach to the data
-    DataValidity validity{DataValidity::ok};
-  };
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  void FeedingFanOut<UserType>::replaceTransferElement(boost::shared_ptr<ChimeraTK::TransferElement>) {
+    // You can't replace anything here. Just do nothing.
+    /// @todo implement properly?
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  void FeedingFanOut<UserType>::interrupt() {
+    // call the interrut sequences of the fan out (interrupts for fan input and all outputs), and the ndRegisterAccessor
+    FanOut<UserType>::interrupt();
+    if(_withReturn) {
+      _returnSlave->interrupt();
+    }
+  }
+
+  /********************************************************************************************************************/
 
 } /* namespace ChimeraTK */
diff --git a/include/Flags.h b/include/Flags.h
index b0756fd1..65385fc5 100644
--- a/include/Flags.h
+++ b/include/Flags.h
@@ -4,6 +4,8 @@
 
 namespace ChimeraTK {
 
+  /********************************************************************************************************************/
+
   /** Struct to define the direction of variables. The main direction is defined
    * with an enum. In addition the presence of a return channel is specified. */
   struct VariableDirection {
@@ -21,12 +23,18 @@ namespace ChimeraTK {
     bool operator!=(const VariableDirection& other) const { return !operator==(other); }
   };
 
+  /********************************************************************************************************************/
+
   /** Enum to define the update mode of variables. */
   enum class UpdateMode { poll, push, invalid };
 
+  /********************************************************************************************************************/
+
   /** Enum to define types of VariableNetworkNode */
   enum class NodeType { Device, ControlSystem, Application, TriggerReceiver, TriggerProvider, Constant, invalid };
 
+  /********************************************************************************************************************/
+
   /** Hierarchy modifier: specify if and how the module hierarchy should be modified in EntityOwner::findTag() etc. */
   enum class HierarchyModifier {
     none,     ///< No modification is performed
@@ -43,6 +51,8 @@ namespace ChimeraTK {
     ///< inside an application.
   };
 
+  /********************************************************************************************************************/
+
   /** Enum to define the life-cycle states of an Application. */
   enum class LifeCycleState {
     initialisation, ///< Initialisation phase including ApplicationModule::prepare(). Single threaded operation. All
@@ -53,4 +63,6 @@ namespace ChimeraTK {
     shutdown ///< The application is in the process of shutting down.
   };
 
+  /********************************************************************************************************************/
+
 } /* namespace ChimeraTK */
diff --git a/include/InternalModule.h b/include/InternalModule.h
index 3f571791..2a9a5a0f 100644
--- a/include/InternalModule.h
+++ b/include/InternalModule.h
@@ -10,6 +10,8 @@
 
 namespace ChimeraTK {
 
+  /********************************************************************************************************************/
+
   /** Base class for internal modules which are created by the variable connection code (e.g.
    *  Application::makeConnections()). These modules have to be handled  differently since the instance is created
    *  dynamically and thus we cannot store the plain pointer in Application::overallModuleList.
@@ -18,7 +20,7 @@ namespace ChimeraTK {
    *  to be properly unified with the normal Module classes. */
   class InternalModule : public EntityOwner {
    public:
-    ~InternalModule() override {}
+    ~InternalModule() override = default;
 
     /** Activate synchronisation thread if needed
      *  @todo: Unify with Module::run() */
@@ -38,16 +40,28 @@ namespace ChimeraTK {
     DataValidity getDataValidity() const override { throw; }
     void incrementDataFaultCounter() override { throw; }
     void decrementDataFaultCounter() override { throw; }
-    std::list<EntityOwner*> getInputModulesRecursively([[maybe_unused]] std::list<EntityOwner*> startList) override {
-      throw ChimeraTK::logic_error("getInputModulesRecursively() called on an InternalModule (ThreadedFanout or "
-                                   "TriggerFanout). This is probably "
-                                   "caused by incorrect ownership of variables/accessors or VariableGroups.");
-    }
-    size_t getCircularNetworkHash() override {
-      throw ChimeraTK::logic_error("getCircularNetworkHash() called on an InternalModule (ThreadedFanout or "
-                                   "TriggerFanout). This is probably "
-                                   "caused by incorrect ownership of variables/accessors or VariableGroups.");
-    }
+    std::list<EntityOwner*> getInputModulesRecursively([[maybe_unused]] std::list<EntityOwner*> startList) override;
+    size_t getCircularNetworkHash() override;
   };
 
+  /********************************************************************************************************************/
+  /********************************************************************************************************************/
+
+  inline std::list<EntityOwner*> InternalModule::getInputModulesRecursively(
+      [[maybe_unused]] std::list<EntityOwner*> startList) {
+    throw ChimeraTK::logic_error("getInputModulesRecursively() called on an InternalModule (ThreadedFanout or "
+                                 "TriggerFanout). This is probably "
+                                 "caused by incorrect ownership of variables/accessors or VariableGroups.");
+  }
+
+  /********************************************************************************************************************/
+
+  inline size_t InternalModule::getCircularNetworkHash() {
+    throw ChimeraTK::logic_error("getCircularNetworkHash() called on an InternalModule (ThreadedFanout or "
+                                 "TriggerFanout). This is probably "
+                                 "caused by incorrect ownership of variables/accessors or VariableGroups.");
+  }
+
+  /********************************************************************************************************************/
+
 } /* namespace ChimeraTK */
diff --git a/include/InversionOfControlAccessor.h b/include/InversionOfControlAccessor.h
index f129c9e7..6913303d 100644
--- a/include/InversionOfControlAccessor.h
+++ b/include/InversionOfControlAccessor.h
@@ -11,6 +11,8 @@
 
 namespace ChimeraTK {
 
+  /********************************************************************************************************************/
+
   /** Adds features required for inversion of control to an accessor. This is
    * needed for both the ArrayAccessor and the ScalarAccessor classes, thus it
    * uses a CRTP. */
@@ -18,21 +20,15 @@ namespace ChimeraTK {
   class InversionOfControlAccessor {
    public:
     /** Unregister at its owner when deleting */
-    ~InversionOfControlAccessor() {
-      if(getOwner() != nullptr) getOwner()->unregisterAccessor(node);
-    }
+    ~InversionOfControlAccessor();
 
     /** Change meta data (name, unit, description and optionally tags). This
      * function may only be used on Application-type nodes. If the optional
      * argument tags is omitted, the tags will not be changed. To clear the
      *  tags, an empty set can be passed. */
-    void setMetaData(const std::string& name, const std::string& unit, const std::string& description) {
-      node.setMetaData(name, unit, completeDescription(getOwner(), description));
-    }
+    void setMetaData(const std::string& name, const std::string& unit, const std::string& description);
     void setMetaData(const std::string& name, const std::string& unit, const std::string& description,
-        const std::unordered_set<std::string>& tags) {
-      node.setMetaData(name, unit, completeDescription(getOwner(), description), tags);
-    }
+        const std::unordered_set<std::string>& tags);
 
     /** Add a tag. Valid names for tags only contain alpha-numeric characters
      * (i.e. no spaces and no special characters). */
@@ -40,9 +36,7 @@ namespace ChimeraTK {
 
     /** Add multiple tags. Valid names for tags only contain alpha-numeric
      * characters (i.e. no spaces and no special characters). */
-    void addTags(const std::unordered_set<std::string>& tags) {
-      for(auto& tag : tags) node.addTag(tag);
-    }
+    void addTags(const std::unordered_set<std::string>& tags);
 
     /** Convert into VariableNetworkNode */
     operator VariableNetworkNode() { return node; }
@@ -52,54 +46,105 @@ namespace ChimeraTK {
     VariableNetworkNode operator>>(const VariableNetworkNode& otherNode) { return node >> otherNode; }
 
     /** Replace with other accessor */
-    void replace(Derived&& other) {
-      assert(static_cast<Derived*>(this)->_impl == nullptr && other._impl == nullptr);
-      if(getOwner() != nullptr) getOwner()->unregisterAccessor(node);
-      node = other.node; // just copies the pointer, but other will be destroyed
-                         // right after this move constructor
-      other.node = VariableNetworkNode();
-      if(node.getType() == NodeType::Application) {
-        node.setAppAccessorPointer(static_cast<Derived*>(this));
-      }
-      else {
-        assert(node.getType() == NodeType::invalid);
-      }
-      // Note: the accessor is registered by the VariableNetworkNode, so we don't
-      // have to re-register.
-    }
+    void replace(Derived&& other);
 
     /** Return the owning module */
     EntityOwner* getOwner() const { return node.getOwningModule(); }
 
    protected:
     /// complete the description with the full description from the owner
-    std::string completeDescription(EntityOwner* owner, const std::string& description) {
-      auto ownerDescription = owner->getFullDescription();
-      if(ownerDescription == "") return description;
-      if(description == "") return ownerDescription;
-      return ownerDescription + " - " + description;
-    }
+    std::string completeDescription(EntityOwner* owner, const std::string& description);
 
     InversionOfControlAccessor(Module* owner, const std::string& name, VariableDirection direction, std::string unit,
         size_t nElements, UpdateMode mode, const std::string& description, const std::type_info* valueType,
-        const std::unordered_set<std::string>& tags = {})
-    : node(owner, static_cast<Derived*>(this), name, direction, unit, nElements, mode,
-          completeDescription(owner, description), valueType, tags) {
-      static_assert(std::is_base_of<InversionOfControlAccessor<Derived>, Derived>::value,
-          "InversionOfControlAccessor<> must be used in a curiously recurring "
-          "template pattern!");
-      if(name.find_first_of("/") != std::string::npos) {
-        throw ChimeraTK::logic_error(
-            "Accessor names must not contain slashes: '" + name + "' in module '" + owner->getQualifiedName() + "'.");
-      }
-      owner->registerAccessor(node);
-    }
+        const std::unordered_set<std::string>& tags = {});
 
     /** Default constructor creates a dysfunctional accessor (to be assigned with
      * a real accessor later) */
-    InversionOfControlAccessor() {}
+    InversionOfControlAccessor() = default;
 
     VariableNetworkNode node;
   };
 
+  /********************************************************************************************************************/
+  /********************************************************************************************************************/
+
+  template<typename Derived>
+  InversionOfControlAccessor<Derived>::~InversionOfControlAccessor() {
+    if(getOwner() != nullptr) getOwner()->unregisterAccessor(node);
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename Derived>
+  void InversionOfControlAccessor<Derived>::setMetaData(
+      const std::string& name, const std::string& unit, const std::string& description) {
+    node.setMetaData(name, unit, completeDescription(getOwner(), description));
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename Derived>
+  void InversionOfControlAccessor<Derived>::setMetaData(const std::string& name, const std::string& unit,
+      const std::string& description, const std::unordered_set<std::string>& tags) {
+    node.setMetaData(name, unit, completeDescription(getOwner(), description), tags);
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename Derived>
+  void InversionOfControlAccessor<Derived>::addTags(const std::unordered_set<std::string>& tags) {
+    for(auto& tag : tags) node.addTag(tag);
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename Derived>
+  void InversionOfControlAccessor<Derived>::replace(Derived&& other) {
+    assert(static_cast<Derived*>(this)->_impl == nullptr && other._impl == nullptr);
+    if(getOwner() != nullptr) getOwner()->unregisterAccessor(node);
+    node = other.node; // just copies the pointer, but other will be destroyed
+                       // right after this move constructor
+    other.node = VariableNetworkNode();
+    if(node.getType() == NodeType::Application) {
+      node.setAppAccessorPointer(static_cast<Derived*>(this));
+    }
+    else {
+      assert(node.getType() == NodeType::invalid);
+    }
+    // Note: the accessor is registered by the VariableNetworkNode, so we don't
+    // have to re-register.
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename Derived>
+  std::string InversionOfControlAccessor<Derived>::completeDescription(
+      EntityOwner* owner, const std::string& description) {
+    auto ownerDescription = owner->getFullDescription();
+    if(ownerDescription == "") return description;
+    if(description == "") return ownerDescription;
+    return ownerDescription + " - " + description;
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename Derived>
+  InversionOfControlAccessor<Derived>::InversionOfControlAccessor(Module* owner, const std::string& name,
+      VariableDirection direction, std::string unit, size_t nElements, UpdateMode mode, const std::string& description,
+      const std::type_info* valueType, const std::unordered_set<std::string>& tags)
+  : node(owner, static_cast<Derived*>(this), name, direction, unit, nElements, mode,
+        completeDescription(owner, description), valueType, tags) {
+    static_assert(std::is_base_of<InversionOfControlAccessor<Derived>, Derived>::value,
+        "InversionOfControlAccessor<> must be used in a curiously recurring "
+        "template pattern!");
+    if(name.find_first_of("/") != std::string::npos) {
+      throw ChimeraTK::logic_error(
+          "Accessor names must not contain slashes: '" + name + "' in module '" + owner->getQualifiedName() + "'.");
+    }
+    owner->registerAccessor(node);
+  }
+
+  /********************************************************************************************************************/
+
 } // namespace ChimeraTK
diff --git a/include/MetaDataPropagatingRegisterDecorator.h b/include/MetaDataPropagatingRegisterDecorator.h
index 200dc3ef..bb9ce2a0 100644
--- a/include/MetaDataPropagatingRegisterDecorator.h
+++ b/include/MetaDataPropagatingRegisterDecorator.h
@@ -4,14 +4,16 @@
 
 #include <ChimeraTK/NDRegisterAccessorDecorator.h>
 
-/********************************************************************************************************************/
-
 namespace ChimeraTK {
 
+  /********************************************************************************************************************/
+
   // we can only declare the classes here but not use them/include the header to avoid a circular dependency
   class EntityOwner;
   class VariableNetworkNode;
 
+  /********************************************************************************************************************/
+
   /**
    *  A mix-in helper class so you can set the flags without knowing the user data type.
    */
@@ -36,6 +38,8 @@ namespace ChimeraTK {
     friend class VariableNetworkNode;
   };
 
+  /********************************************************************************************************************/
+
   /**
    *  NDRegisterAccessorDecorator which propagates meta data attached to input process variables through the owning
    *  ApplicationModule. It will set the current version number of the owning ApplicationModule in postRead. At the
@@ -62,6 +66,10 @@ namespace ChimeraTK {
     using MetaDataPropagationFlagProvider::_isCircularInput;
   };
 
+  /********************************************************************************************************************/
+
   DECLARE_TEMPLATE_FOR_CHIMERATK_USER_TYPES(MetaDataPropagatingRegisterDecorator);
 
+  /********************************************************************************************************************/
+
 } /* namespace ChimeraTK */
diff --git a/include/Module.h b/include/Module.h
index 0bc75641..5af1e25a 100644
--- a/include/Module.h
+++ b/include/Module.h
@@ -10,8 +10,12 @@
 
 namespace ChimeraTK {
 
+  /********************************************************************************************************************/
+
   class ApplicationModule;
 
+  /********************************************************************************************************************/
+
   /** Base class for ApplicationModule, DeviceModule and ControlSystemModule, to
    * have a common interface for these module types. */
   class Module : public EntityOwner {
@@ -121,19 +125,11 @@ namespace ChimeraTK {
      */
     virtual void connectTo(const Module& target, VariableNetworkNode trigger = {}) const = 0;
 
-    std::string getQualifiedName() const override {
-      return ((_owner != nullptr) ? _owner->getQualifiedName() : "") + "/" + _name;
-    }
+    std::string getQualifiedName() const override;
 
     virtual std::string getVirtualQualifiedName() const;
 
-    std::string getFullDescription() const override {
-      if(_owner == nullptr) return _description;
-      auto ownerDescription = _owner->getFullDescription();
-      if(ownerDescription == "") return _description;
-      if(_description == "") return ownerDescription;
-      return ownerDescription + " - " + _description;
-    }
+    std::string getFullDescription() const override;
 
     /** Set a new owner. The caller has to take care himself that the Module gets
      * unregistered with the old owner
@@ -148,14 +144,16 @@ namespace ChimeraTK {
     void accept(Visitor<Module>& visitor) const { visitor.dispatch(*this); }
 
     VersionNumber getCurrentVersionNumber() const override { return _owner->getCurrentVersionNumber(); }
+
     void setCurrentVersionNumber(VersionNumber version) override { _owner->setCurrentVersionNumber(version); }
 
     DataValidity getDataValidity() const override { return _owner->getDataValidity(); }
+
     void incrementDataFaultCounter() override { _owner->incrementDataFaultCounter(); }
+
     void decrementDataFaultCounter() override { _owner->decrementDataFaultCounter(); }
-    std::list<EntityOwner*> getInputModulesRecursively(std::list<EntityOwner*> startList) override {
-      return _owner->getInputModulesRecursively(startList);
-    }
+
+    std::list<EntityOwner*> getInputModulesRecursively(std::list<EntityOwner*> startList) override;
 
     size_t getCircularNetworkHash() override { return _owner->getCircularNetworkHash(); }
 
@@ -174,4 +172,6 @@ namespace ChimeraTK {
     EntityOwner* _owner{nullptr};
   };
 
+  /********************************************************************************************************************/
+
 } /* namespace ChimeraTK */
diff --git a/include/ModuleGroup.h b/include/ModuleGroup.h
index 3213e67a..27ffdb89 100644
--- a/include/ModuleGroup.h
+++ b/include/ModuleGroup.h
@@ -39,13 +39,7 @@ namespace ChimeraTK {
     ModuleGroup(ModuleGroup&& other) { operator=(std::move(other)); }
 
     /** Move assignment */
-    ModuleGroup& operator=(ModuleGroup&& other) {
-      ModuleImpl::operator=(std::move(other));
-      return *this;
-    }
-
-    /** Destructor */
-    virtual ~ModuleGroup(){};
+    ModuleGroup& operator=(ModuleGroup&& other);
 
     ModuleType getModuleType() const override { return ModuleType::ModuleGroup; }
   };
diff --git a/include/ModuleImpl.h b/include/ModuleImpl.h
index b6a9d44f..8fbeda18 100644
--- a/include/ModuleImpl.h
+++ b/include/ModuleImpl.h
@@ -17,25 +17,19 @@ namespace ChimeraTK {
    public:
     // constructor inheritances does not work due to a gcc bug!?
     ModuleImpl(EntityOwner* owner, const std::string& name, const std::string& description,
-        HierarchyModifier hierarchyModifier = HierarchyModifier::none, const std::unordered_set<std::string>& tags = {})
-    : Module(owner, name, description, hierarchyModifier, tags) {}
+        HierarchyModifier hierarchyModifier = HierarchyModifier::none,
+        const std::unordered_set<std::string>& tags = {});
 
     ModuleImpl(EntityOwner* owner, const std::string& name, const std::string& description, bool eliminateHierarchy,
-        const std::unordered_set<std::string>& tags = {})
-    : Module(owner, name, description, eliminateHierarchy, tags) {}
+        const std::unordered_set<std::string>& tags = {});
 
-    ModuleImpl() : Module() {}
+    ModuleImpl() = default;
 
     /** Move constructor */
     ModuleImpl(ModuleImpl&& other) { operator=(std::move(other)); }
 
     /** Move assignment operator */
-    ModuleImpl& operator=(ModuleImpl&& other) {
-      if(other.virtualisedModule_isValid) virtualisedModule = other.virtualisedModule;
-      virtualisedModule_isValid = other.virtualisedModule_isValid;
-      Module::operator=(std::forward<ModuleImpl>(other));
-      return *this;
-    }
+    ModuleImpl& operator=(ModuleImpl&& other);
 
     VariableNetworkNode operator()(const std::string& variableName) const override;
 
diff --git a/include/ScalarAccessor.h b/include/ScalarAccessor.h
index de58d608..fd1c3ac9 100644
--- a/include/ScalarAccessor.h
+++ b/include/ScalarAccessor.h
@@ -33,52 +33,30 @@ namespace ChimeraTK {
     using ChimeraTK::ScalarRegisterAccessor<UserType>::operator=;
 
     /** Move constructor */
-    ScalarAccessor(ScalarAccessor<UserType>&& other) {
-      InversionOfControlAccessor<ScalarAccessor<UserType>>::replace(std::move(other));
-    }
+    ScalarAccessor(ScalarAccessor<UserType>&& other);
 
     /** Move assignment. */
-    ScalarAccessor<UserType>& operator=(ScalarAccessor<UserType>&& other) {
-      // Having a move-assignment operator is required to use the move-assignment
-      // operator of a module containing an accessor.
-      InversionOfControlAccessor<ScalarAccessor<UserType>>::replace(std::move(other));
-      return *this;
-    }
+    ScalarAccessor<UserType>& operator=(ScalarAccessor<UserType>&& other);
 
     bool write(ChimeraTK::VersionNumber versionNumber) = delete;
     bool writeDestructively(ChimeraTK::VersionNumber versionNumber) = delete;
     void writeIfDifferent(UserType newValue, VersionNumber versionNumber) = delete;
 
-    bool write() {
-      auto versionNumber = this->getOwner()->getCurrentVersionNumber();
-      bool dataLoss = ChimeraTK::ScalarRegisterAccessor<UserType>::write(versionNumber);
-      if(dataLoss) Application::incrementDataLossCounter(this->node.getQualifiedName());
-      return dataLoss;
-    }
-
-    bool writeDestructively() {
-      auto versionNumber = this->getOwner()->getCurrentVersionNumber();
-      bool dataLoss = ChimeraTK::ScalarRegisterAccessor<UserType>::writeDestructively(versionNumber);
-      if(dataLoss) Application::incrementDataLossCounter(this->node.getQualifiedName());
-      return dataLoss;
-    }
-
-    void writeIfDifferent(UserType newValue) {
-      auto versionNumber = this->getOwner()->getCurrentVersionNumber();
-      ChimeraTK::ScalarRegisterAccessor<UserType>::writeIfDifferent(newValue, versionNumber);
-    }
+    bool write();
+
+    bool writeDestructively();
+
+    void writeIfDifferent(UserType newValue);
 
    protected:
     friend class InversionOfControlAccessor<ScalarAccessor<UserType>>;
 
     ScalarAccessor(Module* owner, const std::string& name, VariableDirection direction, std::string unit,
-        UpdateMode mode, const std::string& description, const std::unordered_set<std::string>& tags = {})
-    : InversionOfControlAccessor<ScalarAccessor<UserType>>(
-          owner, name, direction, unit, 1, mode, description, &typeid(UserType), tags) {}
+        UpdateMode mode, const std::string& description, const std::unordered_set<std::string>& tags = {});
 
     /** Default constructor creates a dysfunctional accessor (to be assigned with
      * a real accessor later) */
-    ScalarAccessor() {}
+    ScalarAccessor() = default;
   };
 
   /********************************************************************************************************************/
@@ -87,9 +65,7 @@ namespace ChimeraTK {
   template<typename UserType>
   struct ScalarPushInput : public ScalarAccessor<UserType> {
     ScalarPushInput(Module* owner, const std::string& name, std::string unit, const std::string& description,
-        const std::unordered_set<std::string>& tags = {})
-    : ScalarAccessor<UserType>(
-          owner, name, {VariableDirection::consuming, false}, unit, UpdateMode::push, description, tags) {}
+        const std::unordered_set<std::string>& tags = {});
     ScalarPushInput() : ScalarAccessor<UserType>() {}
     using ScalarAccessor<UserType>::operator=;
   };
@@ -100,9 +76,7 @@ namespace ChimeraTK {
   template<typename UserType>
   struct ScalarPollInput : public ScalarAccessor<UserType> {
     ScalarPollInput(Module* owner, const std::string& name, std::string unit, const std::string& description,
-        const std::unordered_set<std::string>& tags = {})
-    : ScalarAccessor<UserType>(
-          owner, name, {VariableDirection::consuming, false}, unit, UpdateMode::poll, description, tags) {}
+        const std::unordered_set<std::string>& tags = {});
     ScalarPollInput() : ScalarAccessor<UserType>() {}
     void read() { this->readLatest(); }
     using ScalarAccessor<UserType>::operator=;
@@ -114,9 +88,7 @@ namespace ChimeraTK {
   template<typename UserType>
   struct ScalarOutput : public ScalarAccessor<UserType> {
     ScalarOutput(Module* owner, const std::string& name, std::string unit, const std::string& description,
-        const std::unordered_set<std::string>& tags = {})
-    : ScalarAccessor<UserType>(
-          owner, name, {VariableDirection::feeding, false}, unit, UpdateMode::push, description, tags) {}
+        const std::unordered_set<std::string>& tags = {});
     ScalarOutput() : ScalarAccessor<UserType>() {}
     using ScalarAccessor<UserType>::operator=;
   };
@@ -127,9 +99,7 @@ namespace ChimeraTK {
   template<typename UserType>
   struct ScalarPushInputWB : public ScalarAccessor<UserType> {
     ScalarPushInputWB(Module* owner, const std::string& name, std::string unit, const std::string& description,
-        const std::unordered_set<std::string>& tags = {})
-    : ScalarAccessor<UserType>(
-          owner, name, {VariableDirection::consuming, true}, unit, UpdateMode::push, description, tags) {}
+        const std::unordered_set<std::string>& tags = {});
     ScalarPushInputWB() : ScalarAccessor<UserType>() {}
     using ScalarAccessor<UserType>::operator=;
   };
@@ -140,13 +110,113 @@ namespace ChimeraTK {
   template<typename UserType>
   struct ScalarOutputPushRB : public ScalarAccessor<UserType> {
     ScalarOutputPushRB(Module* owner, const std::string& name, std::string unit, const std::string& description,
-        const std::unordered_set<std::string>& tags = {})
-    : ScalarAccessor<UserType>(
-          owner, name, {VariableDirection::feeding, true}, unit, UpdateMode::push, description, tags) {}
+        const std::unordered_set<std::string>& tags = {});
     ScalarOutputPushRB() : ScalarAccessor<UserType>() {}
     using ScalarAccessor<UserType>::operator=;
   };
 
   /********************************************************************************************************************/
+  /********************************************************************************************************************/
+  /* Implementations below this point                                                                                 */
+  /********************************************************************************************************************/
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  ScalarAccessor<UserType>::ScalarAccessor(ScalarAccessor<UserType>&& other) {
+    InversionOfControlAccessor<ScalarAccessor<UserType>>::replace(std::move(other));
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  ScalarAccessor<UserType>& ScalarAccessor<UserType>::operator=(ScalarAccessor<UserType>&& other) {
+    // Having a move-assignment operator is required to use the move-assignment
+    // operator of a module containing an accessor.
+    InversionOfControlAccessor<ScalarAccessor<UserType>>::replace(std::move(other));
+    return *this;
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  bool ScalarAccessor<UserType>::write() {
+    auto versionNumber = this->getOwner()->getCurrentVersionNumber();
+    bool dataLoss = ChimeraTK::ScalarRegisterAccessor<UserType>::write(versionNumber);
+    if(dataLoss) Application::incrementDataLossCounter(this->node.getQualifiedName());
+    return dataLoss;
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  bool ScalarAccessor<UserType>::writeDestructively() {
+    auto versionNumber = this->getOwner()->getCurrentVersionNumber();
+    bool dataLoss = ChimeraTK::ScalarRegisterAccessor<UserType>::writeDestructively(versionNumber);
+    if(dataLoss) Application::incrementDataLossCounter(this->node.getQualifiedName());
+    return dataLoss;
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  void ScalarAccessor<UserType>::writeIfDifferent(UserType newValue) {
+    auto versionNumber = this->getOwner()->getCurrentVersionNumber();
+    ChimeraTK::ScalarRegisterAccessor<UserType>::writeIfDifferent(newValue, versionNumber);
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  ScalarAccessor<UserType>::ScalarAccessor(Module* owner, const std::string& name, VariableDirection direction,
+      std::string unit, UpdateMode mode, const std::string& description, const std::unordered_set<std::string>& tags)
+  : InversionOfControlAccessor<ScalarAccessor<UserType>>(
+        owner, name, direction, unit, 1, mode, description, &typeid(UserType), tags) {}
+
+  /********************************************************************************************************************/
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  ScalarPushInput<UserType>::ScalarPushInput(Module* owner, const std::string& name, std::string unit,
+      const std::string& description, const std::unordered_set<std::string>& tags)
+  : ScalarAccessor<UserType>(
+        owner, name, {VariableDirection::consuming, false}, unit, UpdateMode::push, description, tags) {}
+
+  /********************************************************************************************************************/
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  ScalarPollInput<UserType>::ScalarPollInput(Module* owner, const std::string& name, std::string unit,
+      const std::string& description, const std::unordered_set<std::string>& tags)
+  : ScalarAccessor<UserType>(
+        owner, name, {VariableDirection::consuming, false}, unit, UpdateMode::poll, description, tags) {}
+
+  /********************************************************************************************************************/
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  ScalarOutput<UserType>::ScalarOutput(Module* owner, const std::string& name, std::string unit,
+      const std::string& description, const std::unordered_set<std::string>& tags)
+  : ScalarAccessor<UserType>(
+        owner, name, {VariableDirection::feeding, false}, unit, UpdateMode::push, description, tags) {}
+
+  /********************************************************************************************************************/
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  ScalarPushInputWB<UserType>::ScalarPushInputWB(Module* owner, const std::string& name, std::string unit,
+      const std::string& description, const std::unordered_set<std::string>& tags)
+  : ScalarAccessor<UserType>(
+        owner, name, {VariableDirection::consuming, true}, unit, UpdateMode::push, description, tags) {}
+
+  /********************************************************************************************************************/
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  ScalarOutputPushRB<UserType>::ScalarOutputPushRB(Module* owner, const std::string& name, std::string unit,
+      const std::string& description, const std::unordered_set<std::string>& tags)
+  : ScalarAccessor<UserType>(
+        owner, name, {VariableDirection::feeding, true}, unit, UpdateMode::push, description, tags) {}
+
+  /********************************************************************************************************************/
 
 } /* namespace ChimeraTK */
diff --git a/include/SupportedUserTypes.h b/include/SupportedUserTypes.h
index 2c6b84c9..392f12fc 100644
--- a/include/SupportedUserTypes.h
+++ b/include/SupportedUserTypes.h
@@ -2,8 +2,12 @@
 // SPDX-License-Identifier: LGPL-3.0-or-later
 #pragma once
 
+#include <ChimeraTK/SupportedUserTypes.h>
+
 namespace ChimeraTK {
 
+  /********************************************************************************************************************/
+
   /** Map of UserType to value of the UserType. */
   typedef boost::fusion::map<boost::fusion::pair<int8_t, int8_t>, boost::fusion::pair<uint8_t, uint8_t>,
       boost::fusion::pair<int16_t, int16_t>, boost::fusion::pair<uint16_t, uint16_t>,
@@ -11,6 +15,8 @@ namespace ChimeraTK {
       boost::fusion::pair<double, double>>
       ApplicationCoreUserTypeMap;
 
+  /********************************************************************************************************************/
+
   /** Map of UserType to a class template with the UserType as template argument.
    */
   template<template<typename> class TemplateClass>
@@ -24,4 +30,6 @@ namespace ChimeraTK {
         table;
   };
 
+  /********************************************************************************************************************/
+
 } /* namespace ChimeraTK */
diff --git a/include/TestFacility.h b/include/TestFacility.h
index 32bae99c..bc8428dd 100644
--- a/include/TestFacility.h
+++ b/include/TestFacility.h
@@ -15,6 +15,8 @@
 
 namespace ChimeraTK {
 
+  /********************************************************************************************************************/
+
   namespace detail {
 
     template<typename T>
@@ -29,6 +31,8 @@ namespace ChimeraTK {
 
   } // namespace detail
 
+  /********************************************************************************************************************/
+
   /** Helper class to facilitate tests of applications based on ApplicationCore */
   class TestFacility {
    public:
@@ -36,83 +40,15 @@ namespace ChimeraTK {
      * the instance of the TestFacility must not be created before the application
      * (i.e. usually not before the main() routine). The application will
      *  automatically be put into the testable mode and initialised. */
-    explicit TestFacility(bool enableTestableMode = true) {
-      auto pvManagers = createPVManager();
-      pvManager = pvManagers.first;
-      Application::getInstance().setPVManager(pvManagers.second);
-      if(enableTestableMode) Application::getInstance().enableTestableMode();
-      Application::getInstance().initialise();
-    }
+    explicit TestFacility(bool enableTestableMode = true);
 
     /** Start the application in testable mode. */
-    void runApplication() const {
-      Application::getInstance().testFacilityRunApplicationCalled = true;
-      // send default values for all control system variables
-      for(auto& pv : pvManager->getAllProcessVariables()) {
-        callForTypeNoVoid(pv->getValueType(), [&pv, this](auto arg) {
-          // Applies only to writeable variables. @todo FIXME It should also NOT apply for application-to-controlsystem
-          // variables with a return channel, despite being writeable here!
-          if(!pv->isWriteable()) return;
-          // Safety check against incorrect usage
-          if(pv->getVersionNumber() != VersionNumber(nullptr)) {
-            throw ChimeraTK::logic_error("The variable '" + pv->getName() +
-                "' has been written before TestFacility::runApplication() was called. Instead use "
-                "TestFacility::setScalarDefault() resp. setArrayDefault() to set initial values.");
-          }
-          typedef decltype(arg) T;
-          auto pv_casted = boost::dynamic_pointer_cast<NDRegisterAccessor<T>>(pv);
-          auto table = boost::fusion::at_key<T>(defaults.table);
-          // If default value has been stored, copy the default value to the PV.
-          if(table.find(pv->getName()) != table.end()) {
-            /// Since pv_casted is the undecorated PV (lacking the TestableModeAccessorDecorator), we need to copy the
-            /// value also to the decorator. We still have to write through the undecorated PV, otherwise the tests are
-            /// stalled. @todo It is not understood why this happens!
-            /// Decorated accessors are stored in different maps for scalars are arrays...
-            if(pv_casted->getNumberOfSamples() == 1) { // scalar
-              auto accessor = this->getScalar<T>(pv->getName());
-              accessor = table.at(pv->getName())[0];
-            }
-            else { // array
-              auto accessor = this->getArray<T>(pv->getName());
-              accessor = table.at(pv->getName());
-            }
-            // copy value also to undecorated PV
-            pv_casted->accessChannel(0) = table.at(pv->getName());
-          }
-          // Write the initial value. This must be done even if no default value has been stored, since it is expected
-          // by the application.
-          pv_casted->write();
-        });
-      }
-      // start the application
-      Application::getInstance().run();
-      // set thread name
-      Application::registerThread("TestThread");
-      // make sure all initial values have been propagated when in testable mode
-      if(Application::getInstance().isTestableModeEnabled()) {
-        // call stepApplication() only in testable mode and only if the queues are not empty
-        if(Application::getInstance().testableMode_counter != 0 ||
-            Application::getInstance().testableMode_deviceInitialisationCounter != 0) {
-          stepApplication();
-        }
-      }
-
-      // receive all initial values for the control system variables
-      if(Application::getInstance().isTestableModeEnabled()) {
-        for(auto& pv : pvManager->getAllProcessVariables()) {
-          if(!pv->isReadable()) continue;
-          callForTypeNoVoid(pv->getValueType(), [&](auto t) {
-            typedef decltype(t) UserType;
-            this->getArray<UserType>(pv->getName()).readNonBlocking();
-          });
-        }
-      }
-    }
+    void runApplication() const;
 
     /**
      * Check whether data has been sent to the application so stepApplication() can be called.
      */
-    bool canStepApplication() const { return Application::getInstance().canStepApplication(); }
+    bool canStepApplication() const;
 
     /** Perform a "step" of the application. This runs the application until all
      * input provided to it has been processed and all application modules wait
@@ -121,185 +57,49 @@ namespace ChimeraTK {
      * from this function, the result can be checked and new data can be provided
      * to the application. The new data will not be
      *  processed until the next call to step(). */
-    void stepApplication(bool waitForDeviceInitialisation = true) const {
-      Application::getInstance().stepApplication(waitForDeviceInitialisation);
-    }
+    void stepApplication(bool waitForDeviceInitialisation = true) const;
 
     /** Obtain a void process variable from the application, which is published
      * to the control system. */
-    ChimeraTK::VoidRegisterAccessor getVoid(const ChimeraTK::RegisterPath& name) const {
-      // check for existing accessor in cache
-      if(boost::fusion::at_key<ChimeraTK::Void>(accessorMap.table).count(name) > 0) {
-        return boost::fusion::at_key<ChimeraTK::Void>(accessorMap.table)[name];
-      }
-
-      // obtain accessor from ControlSystemPVManager
-      auto pv = pvManager->getProcessArray<ChimeraTK::Void>(name);
-      if(pv == nullptr) {
-        throw ChimeraTK::logic_error("Process variable '" + name + "' does not exist.");
-      }
-
-      // obtain variable id from pvIdMap and transfer it to idMap (required by the
-      // TestableModeAccessorDecorator)
-      size_t varId = Application::getInstance().pvIdMap[pv->getUniqueId()];
-
-      // decorate with TestableModeAccessorDecorator if variable is sender and
-      // receiver is not poll-type, and store it in cache
-      if(pv->isWriteable() && !Application::getInstance().testableMode_isPollMode[varId]) {
-        auto deco = boost::make_shared<TestableModeAccessorDecorator<ChimeraTK::Void>>(pv, false, true, varId, varId);
-        Application::getInstance().testableMode_names[varId] = "ControlSystem:" + name;
-        boost::fusion::at_key<ChimeraTK::Void>(accessorMap.table)[name] = deco;
-      }
-      else {
-        boost::fusion::at_key<ChimeraTK::Void>(accessorMap.table)[name] = pv;
-      }
-
-      // return the accessor as stored in the cache
-      return boost::fusion::at_key<ChimeraTK::Void>(accessorMap.table)[name];
-    }
+    ChimeraTK::VoidRegisterAccessor getVoid(const ChimeraTK::RegisterPath& name) const;
 
     /** Obtain a scalar process variable from the application, which is published
      * to the control system. */
     template<typename T>
-    ChimeraTK::ScalarRegisterAccessor<T> getScalar(const ChimeraTK::RegisterPath& name) const {
-      // check for existing accessor in cache
-      if(boost::fusion::at_key<T>(accessorMap.table).count(name) > 0) {
-        return boost::fusion::at_key<T>(accessorMap.table)[name];
-      }
-
-      // obtain accessor from ControlSystemPVManager
-      auto pv = pvManager->getProcessArray<T>(name);
-      if(pv == nullptr) {
-        throw ChimeraTK::logic_error("Process variable '" + name + "' does not exist.");
-      }
-
-      // obtain variable id from pvIdMap and transfer it to idMap (required by the
-      // TestableModeAccessorDecorator)
-      size_t varId = Application::getInstance().pvIdMap[pv->getUniqueId()];
-
-      // decorate with TestableModeAccessorDecorator if variable is sender and
-      // receiver is not poll-type, and store it in cache
-      if(pv->isWriteable() && !Application::getInstance().testableMode_isPollMode[varId]) {
-        auto deco = boost::make_shared<TestableModeAccessorDecorator<T>>(pv, false, true, varId, varId);
-        Application::getInstance().testableMode_names[varId] = "ControlSystem:" + name;
-        boost::fusion::at_key<T>(accessorMap.table)[name] = deco;
-      }
-      else {
-        boost::fusion::at_key<T>(accessorMap.table)[name] = pv;
-      }
-
-      // return the accessor as stored in the cache
-      return boost::fusion::at_key<T>(accessorMap.table)[name];
-    }
+    ChimeraTK::ScalarRegisterAccessor<T> getScalar(const ChimeraTK::RegisterPath& name) const;
 
     /** Obtain an array-type process variable from the application, which is
      * published to the control system. */
     template<typename T>
-    ChimeraTK::OneDRegisterAccessor<T> getArray(const ChimeraTK::RegisterPath& name) const {
-      // check for existing accessor in cache
-      if(boost::fusion::at_key<T>(accessorMap.table).count(name) > 0) {
-        return boost::fusion::at_key<T>(accessorMap.table)[name];
-      }
-
-      // obtain accessor from ControlSystemPVManager
-      auto pv = pvManager->getProcessArray<T>(name);
-      if(pv == nullptr) {
-        throw ChimeraTK::logic_error("Process variable '" + name + "' does not exist.");
-      }
-
-      // obtain variable id from pvIdMap and transfer it to idMap (required by the
-      // TestableModeAccessorDecorator)
-      size_t varId = Application::getInstance().pvIdMap[pv->getUniqueId()];
-
-      // decorate with TestableModeAccessorDecorator if variable is sender and
-      // receiver is not poll-type, and store it in cache
-      if(pv->isWriteable() && !Application::getInstance().testableMode_isPollMode[varId]) {
-        auto deco = boost::make_shared<TestableModeAccessorDecorator<T>>(pv, false, true, varId, varId);
-        Application::getInstance().testableMode_names[varId] = "ControlSystem:" + name;
-        boost::fusion::at_key<T>(accessorMap.table)[name] = deco;
-      }
-      else {
-        boost::fusion::at_key<T>(accessorMap.table)[name] = pv;
-      }
-
-      // return the accessor as stored in the cache
-      return boost::fusion::at_key<T>(accessorMap.table)[name];
-    }
+    ChimeraTK::OneDRegisterAccessor<T> getArray(const ChimeraTK::RegisterPath& name) const;
 
     /** Convenience function to write a scalar process variable in a single call
      */
     template<typename TYPE>
-    void writeScalar(const std::string& name, const TYPE value) {
-      auto acc = getScalar<typename detail::BoolTypeHelper<TYPE>::type>(name);
-      acc = value;
-      acc.write();
-    }
+    void writeScalar(const std::string& name, const TYPE value);
 
     /** Convenience function to write an array process variable in a single call
      */
     template<typename TYPE>
-    void writeArray(const std::string& name, const std::vector<TYPE>& value) {
-      auto acc = getArray<typename detail::BoolTypeHelper<TYPE>::type>(name);
-      if constexpr(!std::is_same<TYPE, bool>::value) {
-        acc = value;
-      }
-      else {
-        assert(value.size() == acc.getNElements());
-        std::transform(value.begin(), value.end(), acc.begin(), [](const bool& v) -> ChimeraTK::Boolean { return v; });
-      }
-      acc.write();
-    }
+    void writeArray(const std::string& name, const std::vector<TYPE>& value);
 
     /** Convenience function to read the latest value of a scalar process variable
      * in a single call */
     template<typename TYPE>
-    TYPE readScalar(const std::string& name) {
-      auto acc = getScalar<typename detail::BoolTypeHelper<TYPE>::type>(name);
-      acc.readLatest();
-      return acc;
-    }
+    TYPE readScalar(const std::string& name);
 
     /** Convenience function to read the latest value of an array process variable
      * in a single call */
     template<typename TYPE>
-    std::vector<TYPE> readArray(const std::string& name) {
-      auto acc = getArray<typename detail::BoolTypeHelper<TYPE>::type>(name);
-      acc.readLatest();
-      return acc;
-    }
+    std::vector<TYPE> readArray(const std::string& name);
 
     /** Set default value for scalar process variable. */
     template<typename T>
-    void setScalarDefault(const ChimeraTK::RegisterPath& name, const T& value) {
-      if(Application::getInstance().testFacilityRunApplicationCalled) {
-        throw ChimeraTK::logic_error("TestFacility::setScalarDefault() called after runApplication().");
-      }
-      std::vector<T> vv;
-      vv.push_back(value);
-      setArrayDefault(name, vv);
-    }
+    void setScalarDefault(const ChimeraTK::RegisterPath& name, const T& value);
 
     /** Set default value for array process variable. */
     template<typename T>
-    void setArrayDefault(const ChimeraTK::RegisterPath& name, const std::vector<T>& value) {
-      if(Application::getInstance().testFacilityRunApplicationCalled) {
-        throw ChimeraTK::logic_error("TestFacility::setArrayDefault() called after runApplication().");
-      }
-      // check if PV exists
-      auto pv = pvManager->getProcessArray<typename detail::BoolTypeHelper<T>::type>(name);
-      if(pv == nullptr) {
-        throw ChimeraTK::logic_error("Process variable '" + name + "' does not exist.");
-      }
-      // store default value in map
-      auto& tv = boost::fusion::at_key<typename detail::BoolTypeHelper<T>::type>(defaults.table)[name];
-      if constexpr(!std::is_same<T, bool>::value) {
-        tv = value;
-      }
-      else {
-        tv.resize(value.size());
-        std::transform(value.begin(), value.end(), tv.begin(), [](const bool& v) -> ChimeraTK::Boolean { return v; });
-      }
-    }
+    void setArrayDefault(const ChimeraTK::RegisterPath& name, const std::vector<T>& value);
 
    protected:
     boost::shared_ptr<ControlSystemPVManager> pvManager;
@@ -318,4 +118,152 @@ namespace ChimeraTK {
     ChimeraTK::TemplateUserTypeMap<Defaults> defaults;
   };
 
+  /********************************************************************************************************************/
+  /********************************************************************************************************************/
+
+  template<typename T>
+  ChimeraTK::ScalarRegisterAccessor<T> TestFacility::getScalar(const ChimeraTK::RegisterPath& name) const {
+    // check for existing accessor in cache
+    if(boost::fusion::at_key<T>(accessorMap.table).count(name) > 0) {
+      return boost::fusion::at_key<T>(accessorMap.table)[name];
+    }
+
+    // obtain accessor from ControlSystemPVManager
+    auto pv = pvManager->getProcessArray<T>(name);
+    if(pv == nullptr) {
+      throw ChimeraTK::logic_error("Process variable '" + name + "' does not exist.");
+    }
+
+    // obtain variable id from pvIdMap and transfer it to idMap (required by the
+    // TestableModeAccessorDecorator)
+    size_t varId = Application::getInstance().pvIdMap[pv->getUniqueId()];
+
+    // decorate with TestableModeAccessorDecorator if variable is sender and
+    // receiver is not poll-type, and store it in cache
+    if(pv->isWriteable() && !Application::getInstance().testableMode_isPollMode[varId]) {
+      auto deco = boost::make_shared<TestableModeAccessorDecorator<T>>(pv, false, true, varId, varId);
+      Application::getInstance().testableMode_names[varId] = "ControlSystem:" + name;
+      boost::fusion::at_key<T>(accessorMap.table)[name] = deco;
+    }
+    else {
+      boost::fusion::at_key<T>(accessorMap.table)[name] = pv;
+    }
+
+    // return the accessor as stored in the cache
+    return boost::fusion::at_key<T>(accessorMap.table)[name];
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename T>
+  ChimeraTK::OneDRegisterAccessor<T> TestFacility::getArray(const ChimeraTK::RegisterPath& name) const {
+    // check for existing accessor in cache
+    if(boost::fusion::at_key<T>(accessorMap.table).count(name) > 0) {
+      return boost::fusion::at_key<T>(accessorMap.table)[name];
+    }
+
+    // obtain accessor from ControlSystemPVManager
+    auto pv = pvManager->getProcessArray<T>(name);
+    if(pv == nullptr) {
+      throw ChimeraTK::logic_error("Process variable '" + name + "' does not exist.");
+    }
+
+    // obtain variable id from pvIdMap and transfer it to idMap (required by the
+    // TestableModeAccessorDecorator)
+    size_t varId = Application::getInstance().pvIdMap[pv->getUniqueId()];
+
+    // decorate with TestableModeAccessorDecorator if variable is sender and
+    // receiver is not poll-type, and store it in cache
+    if(pv->isWriteable() && !Application::getInstance().testableMode_isPollMode[varId]) {
+      auto deco = boost::make_shared<TestableModeAccessorDecorator<T>>(pv, false, true, varId, varId);
+      Application::getInstance().testableMode_names[varId] = "ControlSystem:" + name;
+      boost::fusion::at_key<T>(accessorMap.table)[name] = deco;
+    }
+    else {
+      boost::fusion::at_key<T>(accessorMap.table)[name] = pv;
+    }
+
+    // return the accessor as stored in the cache
+    return boost::fusion::at_key<T>(accessorMap.table)[name];
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename TYPE>
+  void TestFacility::writeScalar(const std::string& name, const TYPE value) {
+    auto acc = getScalar<typename detail::BoolTypeHelper<TYPE>::type>(name);
+    acc = value;
+    acc.write();
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename TYPE>
+  void TestFacility::writeArray(const std::string& name, const std::vector<TYPE>& value) {
+    auto acc = getArray<typename detail::BoolTypeHelper<TYPE>::type>(name);
+    if constexpr(!std::is_same<TYPE, bool>::value) {
+      acc = value;
+    }
+    else {
+      assert(value.size() == acc.getNElements());
+      std::transform(value.begin(), value.end(), acc.begin(), [](const bool& v) -> ChimeraTK::Boolean { return v; });
+    }
+    acc.write();
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename TYPE>
+  TYPE TestFacility::readScalar(const std::string& name) {
+    auto acc = getScalar<typename detail::BoolTypeHelper<TYPE>::type>(name);
+    acc.readLatest();
+    return acc;
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename TYPE>
+  std::vector<TYPE> TestFacility::readArray(const std::string& name) {
+    auto acc = getArray<typename detail::BoolTypeHelper<TYPE>::type>(name);
+    acc.readLatest();
+    return acc;
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename T>
+  void TestFacility::setScalarDefault(const ChimeraTK::RegisterPath& name, const T& value) {
+    if(Application::getInstance().testFacilityRunApplicationCalled) {
+      throw ChimeraTK::logic_error("TestFacility::setScalarDefault() called after runApplication().");
+    }
+    std::vector<T> vv;
+    vv.push_back(value);
+    setArrayDefault(name, vv);
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename T>
+  void TestFacility::setArrayDefault(const ChimeraTK::RegisterPath& name, const std::vector<T>& value) {
+    if(Application::getInstance().testFacilityRunApplicationCalled) {
+      throw ChimeraTK::logic_error("TestFacility::setArrayDefault() called after runApplication().");
+    }
+    // check if PV exists
+    auto pv = pvManager->getProcessArray<typename detail::BoolTypeHelper<T>::type>(name);
+    if(pv == nullptr) {
+      throw ChimeraTK::logic_error("Process variable '" + name + "' does not exist.");
+    }
+    // store default value in map
+    auto& tv = boost::fusion::at_key<typename detail::BoolTypeHelper<T>::type>(defaults.table)[name];
+    if constexpr(!std::is_same<T, bool>::value) {
+      tv = value;
+    }
+    else {
+      tv.resize(value.size());
+      std::transform(value.begin(), value.end(), tv.begin(), [](const bool& v) -> ChimeraTK::Boolean { return v; });
+    }
+  }
+
+  /********************************************************************************************************************/
+
 } /* namespace ChimeraTK */
diff --git a/include/TestableModeAccessorDecorator.h b/include/TestableModeAccessorDecorator.h
index 807fc81a..0d61ce4a 100644
--- a/include/TestableModeAccessorDecorator.h
+++ b/include/TestableModeAccessorDecorator.h
@@ -9,151 +9,197 @@
 
 namespace ChimeraTK {
 
+  /********************************************************************************************************************/
+
   /** Decorator of the NDRegisterAccessor which facilitates tests of the
    * application */
   template<typename UserType>
   class TestableModeAccessorDecorator : public ChimeraTK::NDRegisterAccessorDecorator<UserType> {
    public:
     TestableModeAccessorDecorator(boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> accessor, bool handleRead,
-        bool handleWrite, size_t variableIdRead, size_t variableIdWrite)
-    : ChimeraTK::NDRegisterAccessorDecorator<UserType>(accessor), _handleRead(handleRead), _handleWrite(handleWrite),
-      _variableIdRead(variableIdRead), _variableIdWrite(variableIdWrite) {
-      assert(_variableIdRead != 0);
-      assert(_variableIdWrite != 0);
-
-      // if receiving end, register for testable mode (stall detection)
-      if(this->isReadable() && handleRead) {
-        Application::getInstance().testableMode_processVars[_variableIdRead] = accessor;
-        assert(accessor->getAccessModeFlags().has(AccessMode::wait_for_new_data));
-      }
+        bool handleWrite, size_t variableIdRead, size_t variableIdWrite);
 
-      // if this decorating a bidirectional process variable, set the
-      // valueRejectCallback
-      auto bidir = boost::dynamic_pointer_cast<BidirectionalProcessArray<UserType>>(accessor);
-      if(bidir) {
-        bidir->setValueRejectCallback([this] { decrementCounter(); });
-      }
-      else {
-        assert(!(handleRead && handleWrite));
-      }
+    bool doWriteTransfer(ChimeraTK::VersionNumber versionNumber = {}) override;
+
+    bool doWriteTransferDestructively(ChimeraTK::VersionNumber versionNumber = {}) override;
+
+    void doReadTransferSynchronously() override { _target->readTransfer(); }
+
+    /** Release the testableModeLock */
+    void releaseLock();
+
+    void doPreRead(TransferType type) override;
+
+    /** Obtain the testableModeLock if not owned yet, and decrement the counter.
+     */
+    void obtainLockAndDecrementCounter(bool hasNewData);
+
+    /** Obtain the testableModeLock if not owned yet, decrement the counter, and
+     * release the lock again. */
+    void decrementCounter();
+
+    void doPostRead(TransferType type, bool hasNewData) override;
+
+   protected:
+    using ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D;
+    using ChimeraTK::NDRegisterAccessorDecorator<UserType>::_target;
+
+    bool _handleRead, _handleWrite;
+    size_t _variableIdRead, _variableIdWrite;
+  };
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  TestableModeAccessorDecorator<UserType>::TestableModeAccessorDecorator(
+      boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> accessor, bool handleRead, bool handleWrite,
+      size_t variableIdRead, size_t variableIdWrite)
+  : ChimeraTK::NDRegisterAccessorDecorator<UserType>(accessor), _handleRead(handleRead), _handleWrite(handleWrite),
+    _variableIdRead(variableIdRead), _variableIdWrite(variableIdWrite) {
+    assert(_variableIdRead != 0);
+    assert(_variableIdWrite != 0);
+
+    // if receiving end, register for testable mode (stall detection)
+    if(this->isReadable() && handleRead) {
+      Application::getInstance().testableMode_processVars[_variableIdRead] = accessor;
+      assert(accessor->getAccessModeFlags().has(AccessMode::wait_for_new_data));
+    }
+
+    // if this decorating a bidirectional process variable, set the
+    // valueRejectCallback
+    auto bidir = boost::dynamic_pointer_cast<BidirectionalProcessArray<UserType>>(accessor);
+    if(bidir) {
+      bidir->setValueRejectCallback([this] { decrementCounter(); });
     }
+    else {
+      assert(!(handleRead && handleWrite));
+    }
+  }
 
-    bool doWriteTransfer(ChimeraTK::VersionNumber versionNumber = {}) override {
-      if(!_handleWrite) return _target->writeTransfer(versionNumber);
+  /********************************************************************************************************************/
 
-      bool dataLost = false;
-      if(!Application::testableModeTestLock()) {
-        // may happen if first write in thread is done before first blocking read
-        Application::testableModeLock("write " + this->getName());
-      }
-      dataLost = _target->writeTransfer(versionNumber);
-      if(!dataLost) {
-        ++Application::getInstance().testableMode_counter;
-        ++Application::getInstance().testableMode_perVarCounter[_variableIdWrite];
-        if(Application::getInstance().enableDebugTestableMode) {
-          std::cout << "TestableModeAccessorDecorator::write[name='" << this->getName() << "', id=" << _variableIdWrite
-                    << "]: testableMode_counter increased, now at value "
-                    << Application::getInstance().testableMode_counter << std::endl;
-        }
+  template<typename UserType>
+  bool TestableModeAccessorDecorator<UserType>::doWriteTransfer(ChimeraTK::VersionNumber versionNumber) {
+    if(!_handleWrite) return _target->writeTransfer(versionNumber);
+
+    bool dataLost = false;
+    if(!Application::testableModeTestLock()) {
+      // may happen if first write in thread is done before first blocking read
+      Application::testableModeLock("write " + this->getName());
+    }
+    dataLost = _target->writeTransfer(versionNumber);
+    if(!dataLost) {
+      ++Application::getInstance().testableMode_counter;
+      ++Application::getInstance().testableMode_perVarCounter[_variableIdWrite];
+      if(Application::getInstance().enableDebugTestableMode) {
+        std::cout << "TestableModeAccessorDecorator::write[name='" << this->getName() << "', id=" << _variableIdWrite
+                  << "]: testableMode_counter increased, now at value "
+                  << Application::getInstance().testableMode_counter << std::endl;
       }
-      else {
-        if(Application::getInstance().enableDebugTestableMode) {
-          std::cout << "TestableModeAccessorDecorator::write[name='" << this->getName() << "', id=" << _variableIdWrite
-                    << "]: testableMode_counter not increased due to lost data" << std::endl;
-        }
+    }
+    else {
+      if(Application::getInstance().enableDebugTestableMode) {
+        std::cout << "TestableModeAccessorDecorator::write[name='" << this->getName() << "', id=" << _variableIdWrite
+                  << "]: testableMode_counter not increased due to lost data" << std::endl;
       }
-      return dataLost;
     }
+    return dataLost;
+  }
 
-    bool doWriteTransferDestructively(ChimeraTK::VersionNumber versionNumber = {}) override {
-      if(!_handleWrite) return _target->writeTransferDestructively(versionNumber);
+  /********************************************************************************************************************/
 
-      bool dataLost = false;
-      if(!Application::testableModeTestLock()) {
-        // may happen if first write in thread is done before first blocking read
-        Application::testableModeLock("write " + this->getName());
-      }
-      dataLost = _target->writeTransferDestructively(versionNumber);
-      if(!dataLost) {
-        ++Application::getInstance().testableMode_counter;
-        ++Application::getInstance().testableMode_perVarCounter[_variableIdWrite];
-        if(Application::getInstance().enableDebugTestableMode) {
-          std::cout << "TestableModeAccessorDecorator::write[name='" << this->getName() << "', id=" << _variableIdWrite
-                    << "]: testableMode_counter increased, now at value "
-                    << Application::getInstance().testableMode_counter << std::endl;
-        }
+  template<typename UserType>
+  bool TestableModeAccessorDecorator<UserType>::doWriteTransferDestructively(ChimeraTK::VersionNumber versionNumber) {
+    if(!_handleWrite) return _target->writeTransferDestructively(versionNumber);
+
+    bool dataLost = false;
+    if(!Application::testableModeTestLock()) {
+      // may happen if first write in thread is done before first blocking read
+      Application::testableModeLock("write " + this->getName());
+    }
+    dataLost = _target->writeTransferDestructively(versionNumber);
+    if(!dataLost) {
+      ++Application::getInstance().testableMode_counter;
+      ++Application::getInstance().testableMode_perVarCounter[_variableIdWrite];
+      if(Application::getInstance().enableDebugTestableMode) {
+        std::cout << "TestableModeAccessorDecorator::write[name='" << this->getName() << "', id=" << _variableIdWrite
+                  << "]: testableMode_counter increased, now at value "
+                  << Application::getInstance().testableMode_counter << std::endl;
       }
-      else {
-        if(Application::getInstance().enableDebugTestableMode) {
-          std::cout << "TestableModeAccessorDecorator::write[name='" << this->getName() << "', id=" << _variableIdWrite
-                    << "]: testableMode_counter not increased due to lost data" << std::endl;
-        }
+    }
+    else {
+      if(Application::getInstance().enableDebugTestableMode) {
+        std::cout << "TestableModeAccessorDecorator::write[name='" << this->getName() << "', id=" << _variableIdWrite
+                  << "]: testableMode_counter not increased due to lost data" << std::endl;
       }
-      return dataLost;
     }
+    return dataLost;
+  }
 
-    void doReadTransferSynchronously() override { _target->readTransfer(); }
+  /********************************************************************************************************************/
 
-    /** Release the testableModeLock */
-    void releaseLock() {
-      if(Application::testableModeTestLock()) Application::testableModeUnlock("doReadTransfer " + this->getName());
-    }
+  template<typename UserType>
+  void TestableModeAccessorDecorator<UserType>::releaseLock() {
+    if(Application::testableModeTestLock()) Application::testableModeUnlock("doReadTransfer " + this->getName());
+  }
 
-    void doPreRead(TransferType type) override {
-      _target->preRead(type);
+  /********************************************************************************************************************/
 
-      // Blocking reads have to release the lock so the data transport can happen
-      if(_handleRead && type == TransferType::read &&
-          TransferElement::_accessModeFlags.has(AccessMode::wait_for_new_data)) {
-        releaseLock();
-      }
+  template<typename UserType>
+  void TestableModeAccessorDecorator<UserType>::doPreRead(TransferType type) {
+    _target->preRead(type);
+
+    // Blocking reads have to release the lock so the data transport can happen
+    if(_handleRead && type == TransferType::read &&
+        TransferElement::_accessModeFlags.has(AccessMode::wait_for_new_data)) {
+      releaseLock();
     }
+  }
 
-    /** Obtain the testableModeLock if not owned yet, and decrement the counter.
-     */
-    void obtainLockAndDecrementCounter(bool hasNewData) {
-      if(!Application::testableModeTestLock()) Application::testableModeLock("doReadTransfer " + this->getName());
-      if(!hasNewData) return;
-      if(Application::getInstance().testableMode_perVarCounter[_variableIdRead] > 0) {
-        assert(Application::getInstance().testableMode_counter > 0);
-        --Application::getInstance().testableMode_counter;
-        --Application::getInstance().testableMode_perVarCounter[_variableIdRead];
-        if(Application::getInstance().enableDebugTestableMode) {
-          std::cout << "TestableModeAccessorDecorator[name='" << this->getName() << "', id=" << _variableIdRead
-                    << "]: testableMode_counter decreased, now at value "
-                    << Application::getInstance().testableMode_counter << " / "
-                    << Application::getInstance().testableMode_perVarCounter[_variableIdRead] << std::endl;
-        }
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  void TestableModeAccessorDecorator<UserType>::obtainLockAndDecrementCounter(bool hasNewData) {
+    if(!Application::testableModeTestLock()) Application::testableModeLock("doReadTransfer " + this->getName());
+    if(!hasNewData) return;
+    if(Application::getInstance().testableMode_perVarCounter[_variableIdRead] > 0) {
+      assert(Application::getInstance().testableMode_counter > 0);
+      --Application::getInstance().testableMode_counter;
+      --Application::getInstance().testableMode_perVarCounter[_variableIdRead];
+      if(Application::getInstance().enableDebugTestableMode) {
+        std::cout << "TestableModeAccessorDecorator[name='" << this->getName() << "', id=" << _variableIdRead
+                  << "]: testableMode_counter decreased, now at value "
+                  << Application::getInstance().testableMode_counter << " / "
+                  << Application::getInstance().testableMode_perVarCounter[_variableIdRead] << std::endl;
       }
-      else {
-        if(Application::getInstance().enableDebugTestableMode) {
-          std::cout << "TestableModeAccessorDecorator[name='" << this->getName() << "', id=" << _variableIdRead
-                    << "]: testableMode_counter NOT decreased, was already at value "
-                    << Application::getInstance().testableMode_counter << " / "
-                    << Application::getInstance().testableMode_perVarCounter[_variableIdRead] << std::endl;
-          std::cout << Application::getInstance().testableMode_names[_variableIdRead] << std::endl;
-        }
+    }
+    else {
+      if(Application::getInstance().enableDebugTestableMode) {
+        std::cout << "TestableModeAccessorDecorator[name='" << this->getName() << "', id=" << _variableIdRead
+                  << "]: testableMode_counter NOT decreased, was already at value "
+                  << Application::getInstance().testableMode_counter << " / "
+                  << Application::getInstance().testableMode_perVarCounter[_variableIdRead] << std::endl;
+        std::cout << Application::getInstance().testableMode_names[_variableIdRead] << std::endl;
       }
     }
+  }
 
-    /** Obtain the testableModeLock if not owned yet, decrement the counter, and
-     * release the lock again. */
-    void decrementCounter() {
-      obtainLockAndDecrementCounter(true);
-      releaseLock();
-    }
+  /********************************************************************************************************************/
 
-    void doPostRead(TransferType type, bool hasNewData) override {
-      if(_handleRead) obtainLockAndDecrementCounter(hasNewData);
-      ChimeraTK::NDRegisterAccessorDecorator<UserType>::doPostRead(type, hasNewData);
-    }
+  template<typename UserType>
+  void TestableModeAccessorDecorator<UserType>::decrementCounter() {
+    obtainLockAndDecrementCounter(true);
+    releaseLock();
+  }
 
-   protected:
-    using ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D;
-    using ChimeraTK::NDRegisterAccessorDecorator<UserType>::_target;
+  /********************************************************************************************************************/
 
-    bool _handleRead, _handleWrite;
-    size_t _variableIdRead, _variableIdWrite;
-  };
+  template<typename UserType>
+  void TestableModeAccessorDecorator<UserType>::doPostRead(TransferType type, bool hasNewData) {
+    if(_handleRead) obtainLockAndDecrementCounter(hasNewData);
+    ChimeraTK::NDRegisterAccessorDecorator<UserType>::doPostRead(type, hasNewData);
+  }
+
+  /********************************************************************************************************************/
 
 } /* namespace ChimeraTK */
diff --git a/include/ThreadedFanOut.h b/include/ThreadedFanOut.h
index bfe38674..201696b8 100644
--- a/include/ThreadedFanOut.h
+++ b/include/ThreadedFanOut.h
@@ -11,6 +11,8 @@
 
 namespace ChimeraTK {
 
+  /********************************************************************************************************************/
+
   /** FanOut implementation with an internal thread which waits for new data which
    * is read from the given feeding implementation and distributed to any number
    * of slaves. */
@@ -18,70 +20,19 @@ namespace ChimeraTK {
   class ThreadedFanOut : public FanOut<UserType>, public InternalModule {
    public:
     ThreadedFanOut(boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> feedingImpl, VariableNetwork& network,
-        ConsumerImplementationPairs<UserType> const& consumerImplementationPairs)
-    : FanOut<UserType>(feedingImpl), _network(network) {
-      assert(feedingImpl->getAccessModeFlags().has(AccessMode::wait_for_new_data));
-      for(auto el : consumerImplementationPairs) {
-        FanOut<UserType>::addSlave(el.first, el.second);
-      }
-    }
+        ConsumerImplementationPairs<UserType> const& consumerImplementationPairs);
 
-    ~ThreadedFanOut() { deactivate(); }
+    ~ThreadedFanOut();
 
-    void activate() override {
-      if(this->_disabled) return;
-      assert(!_thread.joinable());
-      _thread = boost::thread([this] { this->run(); });
-    }
+    void activate() override;
 
-    void deactivate() override {
-      if(_thread.joinable()) {
-        _thread.interrupt();
-        FanOut<UserType>::interrupt();
-        _thread.join();
-      }
-      assert(!_thread.joinable());
-    }
+    void deactivate() override;
 
     /** Synchronise feeder and the consumers. This function is executed in the
      * separate thread. */
-    virtual void run() {
-      Application::registerThread("ThFO" + FanOut<UserType>::impl->getName());
-      Application::testableModeLock("start");
-      testableModeReached = true;
-
-      ChimeraTK::VersionNumber version{nullptr};
-      version = readInitialValues();
-      while(true) {
-        // send out copies to slaves
-        Profiler::startMeasurement();
-        boost::this_thread::interruption_point();
-        auto validity = FanOut<UserType>::impl->dataValidity();
-        for(auto& slave : FanOut<UserType>::slaves) {
-          // do not send copy if no data is expected (e.g. trigger)
-          if(slave->getNumberOfSamples() != 0) {
-            slave->accessChannel(0) = FanOut<UserType>::impl->accessChannel(0);
-          }
-          slave->setDataValidity(validity);
-          bool dataLoss = slave->writeDestructively(version);
-          if(dataLoss) Application::incrementDataLossCounter(slave->getName());
-        }
-        // receive data
-        boost::this_thread::interruption_point();
-        Profiler::stopMeasurement();
-        FanOut<UserType>::impl->read();
-        version = FanOut<UserType>::impl->getVersionNumber();
-      }
-    }
+    virtual void run();
 
-    VersionNumber readInitialValues() {
-      Application::testableModeUnlock("readInitialValues");
-      FanOut<UserType>::impl->read();
-      if(!Application::testableModeTestLock()) {
-        Application::testableModeLock("readInitialValues");
-      }
-      return FanOut<UserType>::impl->getVersionNumber();
-    }
+    VersionNumber readInitialValues();
 
    protected:
     /** Thread handling the synchronisation, if needed */
@@ -98,72 +49,14 @@ namespace ChimeraTK {
   class ThreadedFanOutWithReturn : public ThreadedFanOut<UserType> {
    public:
     ThreadedFanOutWithReturn(boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> feedingImpl,
-        VariableNetwork& network, ConsumerImplementationPairs<UserType> const& consumerImplementationPairs)
-    : ThreadedFanOut<UserType>(feedingImpl, network, consumerImplementationPairs) {
-      for(auto el : consumerImplementationPairs) {
-        // TODO Calling a virtual in the constructor seems odd,
-        //      but works because we want this version's implementation
-        addSlave(el.first, el.second);
-      }
-    }
+        VariableNetwork& network, ConsumerImplementationPairs<UserType> const& consumerImplementationPairs);
 
-    void setReturnChannelSlave(boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> returnChannelSlave) {
-      _returnChannelSlave = returnChannelSlave;
-    }
+    void setReturnChannelSlave(boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> returnChannelSlave);
 
     void addSlave(
-        boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> slave, VariableNetworkNode& consumer) override {
-      // TODO Adding slaves is currently by done by the ThreadedFanOut base class.
-      //      Refactor constructors and addSlaves for all FanOuts?
-      // FanOut<UserType>::addSlave(slave, consumer);
-      if(consumer.getDirection().withReturn) {
-        assert(_returnChannelSlave == nullptr);
-        _returnChannelSlave = slave;
-      }
-    }
+        boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> slave, VariableNetworkNode& consumer) override;
 
-    void run() override {
-      Application::registerThread("ThFO" + FanOut<UserType>::impl->getName());
-      Application::testableModeLock("start");
-      testableModeReached = true;
-
-      TransferElementID var;
-      ChimeraTK::VersionNumber version{nullptr};
-
-      version = readInitialValues();
-
-      ReadAnyGroup group({FanOut<UserType>::impl, _returnChannelSlave});
-      while(true) {
-        // send out copies to slaves
-        for(auto& slave : FanOut<UserType>::slaves) {
-          // do not feed back value returnChannelSlave if it was received from it
-          if(slave->getId() == var) continue;
-          // do not send copy if no data is expected (e.g. trigger)
-          if(slave->getNumberOfSamples() != 0) {
-            slave->accessChannel(0) = FanOut<UserType>::impl->accessChannel(0);
-          }
-          bool dataLoss = slave->writeDestructively(version);
-          if(dataLoss) Application::incrementDataLossCounter(slave->getName());
-        }
-        // receive data
-        boost::this_thread::interruption_point();
-        Profiler::stopMeasurement();
-        var = group.readAny();
-        Profiler::startMeasurement();
-        boost::this_thread::interruption_point();
-        // if the update came through the return channel, return it to the feeder
-        if(var == _returnChannelSlave->getId()) {
-          FanOut<UserType>::impl->accessChannel(0).swap(_returnChannelSlave->accessChannel(0));
-          if(version < _returnChannelSlave->getVersionNumber()) {
-            version = _returnChannelSlave->getVersionNumber();
-          }
-          FanOut<UserType>::impl->write(version);
-        }
-        else {
-          version = FanOut<UserType>::impl->getVersionNumber();
-        }
-      }
-    }
+    void run() override;
 
    protected:
     /** Thread handling the synchronisation, if needed */
@@ -176,4 +69,174 @@ namespace ChimeraTK {
     using EntityOwner::testableModeReached;
   };
 
+  /********************************************************************************************************************/
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  ThreadedFanOut<UserType>::ThreadedFanOut(boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> feedingImpl,
+      VariableNetwork& network, ConsumerImplementationPairs<UserType> const& consumerImplementationPairs)
+  : FanOut<UserType>(feedingImpl), _network(network) {
+    assert(feedingImpl->getAccessModeFlags().has(AccessMode::wait_for_new_data));
+    for(auto el : consumerImplementationPairs) {
+      FanOut<UserType>::addSlave(el.first, el.second);
+    }
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  ThreadedFanOut<UserType>::~ThreadedFanOut() {
+    deactivate();
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  void ThreadedFanOut<UserType>::activate() {
+    if(this->_disabled) return;
+    assert(!_thread.joinable());
+    _thread = boost::thread([this] { this->run(); });
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  void ThreadedFanOut<UserType>::deactivate() {
+    if(_thread.joinable()) {
+      _thread.interrupt();
+      FanOut<UserType>::interrupt();
+      _thread.join();
+    }
+    assert(!_thread.joinable());
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  void ThreadedFanOut<UserType>::run() {
+    Application::registerThread("ThFO" + FanOut<UserType>::impl->getName());
+    Application::testableModeLock("start");
+    testableModeReached = true;
+
+    ChimeraTK::VersionNumber version{nullptr};
+    version = readInitialValues();
+    while(true) {
+      // send out copies to slaves
+      Profiler::startMeasurement();
+      boost::this_thread::interruption_point();
+      auto validity = FanOut<UserType>::impl->dataValidity();
+      for(auto& slave : FanOut<UserType>::slaves) {
+        // do not send copy if no data is expected (e.g. trigger)
+        if(slave->getNumberOfSamples() != 0) {
+          slave->accessChannel(0) = FanOut<UserType>::impl->accessChannel(0);
+        }
+        slave->setDataValidity(validity);
+        bool dataLoss = slave->writeDestructively(version);
+        if(dataLoss) Application::incrementDataLossCounter(slave->getName());
+      }
+      // receive data
+      boost::this_thread::interruption_point();
+      Profiler::stopMeasurement();
+      FanOut<UserType>::impl->read();
+      version = FanOut<UserType>::impl->getVersionNumber();
+    }
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  VersionNumber ThreadedFanOut<UserType>::readInitialValues() {
+    Application::testableModeUnlock("readInitialValues");
+    FanOut<UserType>::impl->read();
+    if(!Application::testableModeTestLock()) {
+      Application::testableModeLock("readInitialValues");
+    }
+    return FanOut<UserType>::impl->getVersionNumber();
+  }
+
+  /********************************************************************************************************************/
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  ThreadedFanOutWithReturn<UserType>::ThreadedFanOutWithReturn(
+      boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> feedingImpl, VariableNetwork& network,
+      ConsumerImplementationPairs<UserType> const& consumerImplementationPairs)
+  : ThreadedFanOut<UserType>(feedingImpl, network, consumerImplementationPairs) {
+    for(auto el : consumerImplementationPairs) {
+      // TODO Calling a virtual in the constructor seems odd,
+      //      but works because we want this version's implementation
+      addSlave(el.first, el.second);
+    }
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  void ThreadedFanOutWithReturn<UserType>::setReturnChannelSlave(
+      boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> returnChannelSlave) {
+    _returnChannelSlave = returnChannelSlave;
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  void ThreadedFanOutWithReturn<UserType>::addSlave(
+      boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> slave, VariableNetworkNode& consumer) {
+    // TODO Adding slaves is currently by done by the ThreadedFanOut base class.
+    //      Refactor constructors and addSlaves for all FanOuts?
+    // FanOut<UserType>::addSlave(slave, consumer);
+    if(consumer.getDirection().withReturn) {
+      assert(_returnChannelSlave == nullptr);
+      _returnChannelSlave = slave;
+    }
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  void ThreadedFanOutWithReturn<UserType>::run() {
+    Application::registerThread("ThFO" + FanOut<UserType>::impl->getName());
+    Application::testableModeLock("start");
+    testableModeReached = true;
+
+    TransferElementID var;
+    ChimeraTK::VersionNumber version{nullptr};
+
+    version = readInitialValues();
+
+    ReadAnyGroup group({FanOut<UserType>::impl, _returnChannelSlave});
+    while(true) {
+      // send out copies to slaves
+      for(auto& slave : FanOut<UserType>::slaves) {
+        // do not feed back value returnChannelSlave if it was received from it
+        if(slave->getId() == var) continue;
+        // do not send copy if no data is expected (e.g. trigger)
+        if(slave->getNumberOfSamples() != 0) {
+          slave->accessChannel(0) = FanOut<UserType>::impl->accessChannel(0);
+        }
+        bool dataLoss = slave->writeDestructively(version);
+        if(dataLoss) Application::incrementDataLossCounter(slave->getName());
+      }
+      // receive data
+      boost::this_thread::interruption_point();
+      Profiler::stopMeasurement();
+      var = group.readAny();
+      Profiler::startMeasurement();
+      boost::this_thread::interruption_point();
+      // if the update came through the return channel, return it to the feeder
+      if(var == _returnChannelSlave->getId()) {
+        FanOut<UserType>::impl->accessChannel(0).swap(_returnChannelSlave->accessChannel(0));
+        if(version < _returnChannelSlave->getVersionNumber()) {
+          version = _returnChannelSlave->getVersionNumber();
+        }
+        FanOut<UserType>::impl->write(version);
+      }
+      else {
+        version = FanOut<UserType>::impl->getVersionNumber();
+      }
+    }
+  }
+
+  /********************************************************************************************************************/
+
 } /* namespace ChimeraTK */
diff --git a/include/TriggerFanOut.h b/include/TriggerFanOut.h
index 57201d2e..c5f68c30 100644
--- a/include/TriggerFanOut.h
+++ b/include/TriggerFanOut.h
@@ -16,31 +16,20 @@ constexpr useconds_t DeviceOpenTimeout = 500;
 
 namespace ChimeraTK {
 
+  /********************************************************************************************************************/
+
   /** InternalModule which waits for a trigger, then reads a number of variables
    * and distributes each of them to any number of slaves. */
   class TriggerFanOut : public InternalModule {
    public:
     TriggerFanOut(const boost::shared_ptr<ChimeraTK::TransferElement>& externalTriggerImpl, DeviceModule& deviceModule,
-        VariableNetwork& network)
-    : externalTrigger(externalTriggerImpl), _deviceModule(deviceModule), _network(network) {}
-
-    ~TriggerFanOut() { deactivate(); }
-
-    void activate() override {
-      assert(!_thread.joinable());
-      _thread = boost::thread([this] { this->run(); });
-    }
-
-    void deactivate() override {
-      if(_thread.joinable()) {
-        _thread.interrupt();
-        if(externalTrigger->getAccessModeFlags().has(AccessMode::wait_for_new_data)) {
-          externalTrigger->interrupt();
-        }
-        _thread.join();
-      }
-      assert(!_thread.joinable());
-    }
+        VariableNetwork& network);
+
+    ~TriggerFanOut();
+
+    void activate() override;
+
+    void deactivate() override;
 
     /** Add a new network the TriggerFanOut. The network is defined by its feeding
      * node. This function will return the corresponding FeedingFanOut, to which
@@ -48,89 +37,13 @@ namespace ChimeraTK {
     template<typename UserType>
     boost::shared_ptr<FeedingFanOut<UserType>> addNetwork(
         boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> feedingNode,
-        ConsumerImplementationPairs<UserType> const& consumerImplementationPairs) {
-      assert(feedingNode.get() != nullptr);
-      transferGroup.addAccessor(feedingNode);
-      auto feedingFanOut = boost::make_shared<FeedingFanOut<UserType>>(feedingNode->getName(), feedingNode->getUnit(),
-          feedingNode->getDescription(), feedingNode->getNumberOfSamples(),
-          false, // in TriggerFanOuts we cannot have return channels
-          consumerImplementationPairs);
-      boost::fusion::at_key<UserType>(fanOutMap.table)[feedingNode] = feedingFanOut;
-      return feedingFanOut;
-    }
+        ConsumerImplementationPairs<UserType> const& consumerImplementationPairs);
 
     /** Synchronise feeder and the consumers. This function is executed in the
      * separate thread. */
-    void run() {
-      Application::registerThread("TrFO" + externalTrigger->getName());
-      Application::testableModeLock("start");
-      testableModeReached = true;
-
-      ChimeraTK::VersionNumber version = Application::getInstance().getStartVersion();
-
-      // Wait for the initial value of the trigger. There always will be one, and if we don't read it here we would
-      // trigger the loop twice.
-      externalTrigger->read();
-      version = externalTrigger->getVersionNumber();
-
-      // Wait until the device has been initialised for the first time. This means it
-      // has been opened, and the check in TransferGroup::read() will not throw a logic_error
-      // We don't have to store the lock. Just need it as a synchronisation point.
-      // But we have to increase the testable mode counter because we don't want to fall out of testable mode at this
-      // point already.
-      if(Application::getInstance().testableMode) ++Application::getInstance().testableMode_deviceInitialisationCounter;
-      Application::testableModeUnlock("WaitInitialValueLock");
-      (void)_deviceModule.waitForInitialValues();
-      Application::testableModeLock("Enter while loop");
-      if(Application::getInstance().testableMode) --Application::getInstance().testableMode_deviceInitialisationCounter;
-
-      while(true) {
-        transferGroup.read();
-        // send the version number to the consumers
-        boost::fusion::for_each(fanOutMap.table, SendDataToConsumers(version, externalTrigger->dataValidity()));
-
-        // wait for external trigger
-        boost::this_thread::interruption_point();
-        Profiler::stopMeasurement();
-        externalTrigger->read();
-        Profiler::startMeasurement();
-        boost::this_thread::interruption_point();
-        version = externalTrigger->getVersionNumber();
-      }
-    }
+    void run();
 
    protected:
-    /** Functor class to send data to the consumers, suitable for
-     * boost::fusion::for_each(). */
-    struct SendDataToConsumers {
-      SendDataToConsumers(VersionNumber version, DataValidity triggerValidity)
-      : _version(version), _triggerValidity(triggerValidity) {}
-
-      template<typename PAIR>
-      void operator()(PAIR& pair) const {
-        auto theMap = pair.second; // map of feeder to FeedingFanOut (i.e. part of
-                                   // the fanOutMap)
-
-        // iterate over all feeder/FeedingFanOut pairs
-        for(auto& network : theMap) {
-          auto feeder = network.first;
-          auto fanOut = network.second;
-          fanOut->setDataValidity((_triggerValidity == DataValidity::ok && feeder->dataValidity() == DataValidity::ok) ?
-                  DataValidity::ok :
-                  DataValidity::faulty);
-          fanOut->accessChannel(0).swap(feeder->accessChannel(0));
-          // don't use write destructively. In case of an exception we still need the data for the next read (see
-          // Exception Handling spec B.2.2.6)
-          bool dataLoss = fanOut->write(_version);
-          if(dataLoss) Application::incrementDataLossCounter(fanOut->getName());
-          // swap the data back to the feeder so we have a valid copy there.
-          fanOut->accessChannel(0).swap(feeder->accessChannel(0));
-        }
-      }
-
-      VersionNumber _version;
-      DataValidity _triggerValidity;
-    };
 
     /** TransferElement acting as our trigger */
     boost::shared_ptr<ChimeraTK::TransferElement> externalTrigger;
@@ -155,4 +68,23 @@ namespace ChimeraTK {
     VariableNetwork& _network;
   };
 
+  /********************************************************************************************************************/
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  boost::shared_ptr<FeedingFanOut<UserType>> TriggerFanOut::addNetwork(
+      boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> feedingNode,
+      ConsumerImplementationPairs<UserType> const& consumerImplementationPairs) {
+    assert(feedingNode.get() != nullptr);
+    transferGroup.addAccessor(feedingNode);
+    auto feedingFanOut = boost::make_shared<FeedingFanOut<UserType>>(feedingNode->getName(), feedingNode->getUnit(),
+        feedingNode->getDescription(), feedingNode->getNumberOfSamples(),
+        false, // in TriggerFanOuts we cannot have return channels
+        consumerImplementationPairs);
+    boost::fusion::at_key<UserType>(fanOutMap.table)[feedingNode] = feedingFanOut;
+    return feedingFanOut;
+  }
+
+  /********************************************************************************************************************/
+
 } /* namespace ChimeraTK */
diff --git a/include/VariableGroup.h b/include/VariableGroup.h
index 7a47c251..c842cc4e 100644
--- a/include/VariableGroup.h
+++ b/include/VariableGroup.h
@@ -10,9 +10,13 @@
 
 namespace ChimeraTK {
 
+  /********************************************************************************************************************/
+
   class ApplicationModule;
   struct ConfigReader;
 
+  /********************************************************************************************************************/
+
   class VariableGroup : public ModuleImpl {
    public:
     /** Constructor: Create ModuleGroup by the given name with the given description and register it with its
@@ -36,21 +40,20 @@ namespace ChimeraTK {
      * to allow constructor inheritance of modules owning other modules. This
      * constructor will not actually be called then. See this bug report:
      * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67054 */
-    VariableGroup() {}
+    VariableGroup() = default;
 
     /** Destructor */
-    virtual ~VariableGroup(){};
+    virtual ~VariableGroup() = default;
 
     /** Move constructor */
     VariableGroup(VariableGroup&& other) { operator=(std::move(other)); }
 
     /** Move assignment */
-    VariableGroup& operator=(VariableGroup&& other) {
-      ModuleImpl::operator=(std::move(other));
-      return *this;
-    }
+    VariableGroup& operator=(VariableGroup&& other);
 
     ModuleType getModuleType() const override { return ModuleType::VariableGroup; }
   };
 
+  /********************************************************************************************************************/
+
 } /* namespace ChimeraTK */
diff --git a/include/VariableNetwork.h b/include/VariableNetwork.h
index e1580772..404a4d90 100644
--- a/include/VariableNetwork.h
+++ b/include/VariableNetwork.h
@@ -83,11 +83,7 @@ namespace ChimeraTK {
     void accept(Visitor<VariableNetwork>& visitor) const;
 
     /** Compare two networks */
-    bool operator==(const VariableNetwork& other) const {
-      if(other.valueType != valueType) return false;
-      if(other.nodeList != nodeList) return false;
-      return true;
-    }
+    bool operator==(const VariableNetwork& other) const;
     bool operator!=(const VariableNetwork& other) const { return !operator==(other); }
 
     /** Return the trigger type. This function will also do some checking if the
diff --git a/include/VariableNetworkDumpingVisitor.h b/include/VariableNetworkDumpingVisitor.h
index 4091a79f..1440e3df 100644
--- a/include/VariableNetworkDumpingVisitor.h
+++ b/include/VariableNetworkDumpingVisitor.h
@@ -9,9 +9,13 @@
 
 namespace ChimeraTK {
 
+  /*********************************************************************************************************************/
+
   // Forward declarations
   class VariableNetwork;
 
+  /*********************************************************************************************************************/
+
   /**
    * @brief The VariableNetworkDumpingVisitor class
    *
@@ -28,4 +32,6 @@ namespace ChimeraTK {
     std::string _prefix;
   };
 
+  /*********************************************************************************************************************/
+
 } // namespace ChimeraTK
diff --git a/include/VariableNetworkGraphDumpingVisitor.h b/include/VariableNetworkGraphDumpingVisitor.h
index 5f55a146..0c1e32aa 100644
--- a/include/VariableNetworkGraphDumpingVisitor.h
+++ b/include/VariableNetworkGraphDumpingVisitor.h
@@ -9,11 +9,14 @@
 
 namespace ChimeraTK {
 
-  // Forward Declarations
+  /*********************************************************************************************************************/
 
+  // Forward Declarations
   class Application;
   class VariableNetwork;
 
+  /*********************************************************************************************************************/
+
   /**
    * @brief The VariableNetworkGraphDumpingVisitor class
    *
@@ -42,4 +45,6 @@ namespace ChimeraTK {
     void popPrefix() { _prefix.pop_back(); }
   };
 
+  /*********************************************************************************************************************/
+
 } // namespace ChimeraTK
diff --git a/include/VariableNetworkModuleGraphDumpingVisitor.h b/include/VariableNetworkModuleGraphDumpingVisitor.h
index d304cf0a..4fdbdbb2 100644
--- a/include/VariableNetworkModuleGraphDumpingVisitor.h
+++ b/include/VariableNetworkModuleGraphDumpingVisitor.h
@@ -9,12 +9,15 @@
 
 namespace ChimeraTK {
 
-  // Forward Declarations
+  /*********************************************************************************************************************/
 
+  // Forward Declarations
   class Application;
   class VariableNetwork;
   class Module;
 
+  /*********************************************************************************************************************/
+
   /**
    * @brief The VariableNetworkModuleGraphDumpingVisitor class
    *
@@ -38,4 +41,6 @@ namespace ChimeraTK {
     std::list<std::string> _deviceList;
   };
 
+  /*********************************************************************************************************************/
+
 } // namespace ChimeraTK
diff --git a/include/VariableNetworkNode.h b/include/VariableNetworkNode.h
index 1eb5e17d..1808670d 100644
--- a/include/VariableNetworkNode.h
+++ b/include/VariableNetworkNode.h
@@ -18,14 +18,20 @@
 
 namespace ChimeraTK {
 
+  /********************************************************************************************************************/
+
   class VariableNetwork;
   class AccessorBase;
   class EntityOwner;
   struct VariableNetworkNode_data;
 
+  /********************************************************************************************************************/
+
   /** Pseudo type to identify nodes which can have arbitrary types */
   class AnyType {};
 
+  /********************************************************************************************************************/
+
   /** Class describing a node of a variable network */
   class VariableNetworkNode {
    public:
@@ -186,7 +192,7 @@ namespace ChimeraTK {
     boost::shared_ptr<VariableNetworkNode_data> pdata;
   };
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   /** A helper class to create accessors with the right length and value. We use this
    *  to create one constant accessor for each consumer so e don't have to use a fanout: The consumers might be mixed
@@ -202,7 +208,7 @@ namespace ChimeraTK {
     virtual ~ConstantAccessorCreator() {}
   };
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   /** We use a pimpl pattern so copied instances of VariableNetworkNode refer to
    * the same instance of the data structure and thus stay consistent all the
@@ -275,7 +281,7 @@ namespace ChimeraTK {
     size_t circularNetworkHash{0};
   };
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   // Templated implementation of the ConstantAccessorCreator
   template<typename UserType>
@@ -290,10 +296,9 @@ namespace ChimeraTK {
     }
   };
 
-  /*********************************************************************************************************************/
-  /*** Implementations
-   * *************************************************************************************************/
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
+  /*** Implementations ************************************************************************************************/
+  /********************************************************************************************************************/
 
   template<typename UserType>
   VariableNetworkNode VariableNetworkNode::makeConstant(bool makeFeeder, UserType value, size_t length) {
@@ -315,7 +320,7 @@ namespace ChimeraTK {
     return node;
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   template<typename UserType>
   ChimeraTK::NDRegisterAccessorAbstractor<UserType>& VariableNetworkNode::getAppAccessor() const {
@@ -326,7 +331,7 @@ namespace ChimeraTK {
     return *accessor;
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   template<typename UserType>
   boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> VariableNetworkNode::createConstAccessor(
@@ -335,7 +340,7 @@ namespace ChimeraTK {
         pdata->constNodeCreator->create(accessModeFlags));
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   template<typename UserType>
   void VariableNetworkNode::setAppAccessorImplementation(boost::shared_ptr<NDRegisterAccessor<UserType>> impl) const {
@@ -345,4 +350,6 @@ namespace ChimeraTK {
     assert(flagProvider);
   }
 
+  /********************************************************************************************************************/
+
 } /* namespace ChimeraTK */
diff --git a/include/VariableNetworkNodeDumpingVisitor.h b/include/VariableNetworkNodeDumpingVisitor.h
index 1393f288..8a753037 100644
--- a/include/VariableNetworkNodeDumpingVisitor.h
+++ b/include/VariableNetworkNodeDumpingVisitor.h
@@ -10,9 +10,13 @@
 
 namespace ChimeraTK {
 
+  /********************************************************************************************************************/
+
   // Forward declarations
   class VariableNetworkNode;
 
+  /********************************************************************************************************************/
+
   /**
    * @brief A helper class to replace the output stream temporarily
    *
@@ -41,6 +45,8 @@ namespace ChimeraTK {
     std::list<std::reference_wrapper<std::ostream>> _streamStack;
   };
 
+  /********************************************************************************************************************/
+
   /**
    * @brief The VariableNetworkNodeDumpingVisitor class
    *
@@ -74,4 +80,6 @@ namespace ChimeraTK {
     std::string _separator;
   };
 
+  /********************************************************************************************************************/
+
 } // namespace ChimeraTK
diff --git a/include/VirtualModule.h b/include/VirtualModule.h
index 9f6fde89..922983f7 100644
--- a/include/VirtualModule.h
+++ b/include/VirtualModule.h
@@ -16,12 +16,7 @@ namespace ChimeraTK {
   class VirtualModule : public Module {
    public:
     /** Constructor */
-    VirtualModule(const std::string& name, const std::string& description, ModuleType moduleType)
-    : Module(nullptr, name, description), _moduleType(moduleType) {
-      if(name.find_first_of("/") != std::string::npos) {
-        throw ChimeraTK::logic_error("Module names must not contain slashes: '" + name + "'.");
-      }
-    }
+    VirtualModule(const std::string& name, const std::string& description, ModuleType moduleType);
 
     /** Copy constructor */
     VirtualModule(const VirtualModule& other);
diff --git a/include/Visitor.h b/include/Visitor.h
index 8ae951eb..ea5e3a6a 100644
--- a/include/Visitor.h
+++ b/include/Visitor.h
@@ -4,19 +4,28 @@
 
 namespace ChimeraTK {
 
-  /* Losely based on
+  /********************************************************************************************************************/
+
+  /*
+   * Losely based on
    * https://stackoverflow.com/questions/11796121/implementing-the-visitor-pattern-using-c-templates#11802080
    */
 
+  /********************************************************************************************************************/
+
   template<typename... Types>
   class Visitor;
 
+  /********************************************************************************************************************/
+
   template<typename T>
   class Visitor<T> {
    public:
     virtual void dispatch(const T& t) = 0;
   };
 
+  /********************************************************************************************************************/
+
   template<typename T, typename... Types>
   class Visitor<T, Types...> : public Visitor<T>, public Visitor<Types...> {
    public:
@@ -24,4 +33,6 @@ namespace ChimeraTK {
     using Visitor<T>::dispatch;
   };
 
+  /********************************************************************************************************************/
+
 } // namespace ChimeraTK
diff --git a/include/VoidAccessor.h b/include/VoidAccessor.h
index f69c514a..304a0d84 100644
--- a/include/VoidAccessor.h
+++ b/include/VoidAccessor.h
@@ -28,38 +28,21 @@ namespace ChimeraTK {
     VoidAccessor(VoidAccessor&& other) noexcept { InversionOfControlAccessor<VoidAccessor>::replace(std::move(other)); }
 
     /** Move assignment. */
-    VoidAccessor& operator=(VoidAccessor&& other) noexcept {
-      // Having a move-assignment operator is required to use the move-assignment
-      // operator of a module containing an accessor.
-      InversionOfControlAccessor<VoidAccessor>::replace(std::move(other));
-      return *this;
-    }
+    VoidAccessor& operator=(VoidAccessor&& other) noexcept;
 
     bool write(ChimeraTK::VersionNumber versionNumber) = delete;
     bool writeDestructively(ChimeraTK::VersionNumber versionNumber) = delete;
     // void writeIfDifferent(UserType newValue, VersionNumber versionNumber) = delete;
 
-    bool write() {
-      auto versionNumber = this->getOwner()->getCurrentVersionNumber();
-      bool dataLoss = ChimeraTK::VoidRegisterAccessor::write(versionNumber);
-      if(dataLoss) Application::incrementDataLossCounter(this->node.getQualifiedName());
-      return dataLoss;
-    }
+    bool write();
 
-    bool writeDestructively() {
-      auto versionNumber = this->getOwner()->getCurrentVersionNumber();
-      bool dataLoss = ChimeraTK::VoidRegisterAccessor::writeDestructively(versionNumber);
-      if(dataLoss) Application::incrementDataLossCounter(this->node.getQualifiedName());
-      return dataLoss;
-    }
+    bool writeDestructively();
 
    protected:
     friend class InversionOfControlAccessor<VoidAccessor>;
 
     VoidAccessor(Module* owner, const std::string& name, VariableDirection direction, std::string& unit,
-        UpdateMode mode, const std::string& description, const std::unordered_set<std::string>& tags = {})
-    : InversionOfControlAccessor<VoidAccessor>(
-          owner, name, direction, unit, 1, mode, description, &typeid(ChimeraTK::Void), tags) {}
+        UpdateMode mode, const std::string& description, const std::unordered_set<std::string>& tags = {});
 
     /** Default constructor creates a dysfunctional accessor (to be assigned with a real accessor later) */
     VoidAccessor() = default;
@@ -88,5 +71,43 @@ namespace ChimeraTK {
   };
 
   /********************************************************************************************************************/
+  /********************************************************************************************************************/
+  /* Implementations below this point                                                                                 */
+  /********************************************************************************************************************/
+  /********************************************************************************************************************/
+
+  inline VoidAccessor& VoidAccessor::operator=(VoidAccessor&& other) noexcept {
+    // Having a move-assignment operator is required to use the move-assignment
+    // operator of a module containing an accessor.
+    InversionOfControlAccessor<VoidAccessor>::replace(std::move(other));
+    return *this;
+  }
+
+  /********************************************************************************************************************/
+
+  inline bool VoidAccessor::write() {
+    auto versionNumber = this->getOwner()->getCurrentVersionNumber();
+    bool dataLoss = ChimeraTK::VoidRegisterAccessor::write(versionNumber);
+    if(dataLoss) Application::incrementDataLossCounter(this->node.getQualifiedName());
+    return dataLoss;
+  }
+
+  /********************************************************************************************************************/
+
+  inline bool VoidAccessor::writeDestructively() {
+    auto versionNumber = this->getOwner()->getCurrentVersionNumber();
+    bool dataLoss = ChimeraTK::VoidRegisterAccessor::writeDestructively(versionNumber);
+    if(dataLoss) Application::incrementDataLossCounter(this->node.getQualifiedName());
+    return dataLoss;
+  }
+
+  /********************************************************************************************************************/
+
+  inline VoidAccessor::VoidAccessor(Module* owner, const std::string& name, VariableDirection direction,
+      std::string& unit, UpdateMode mode, const std::string& description, const std::unordered_set<std::string>& tags)
+  : InversionOfControlAccessor<VoidAccessor>(
+        owner, name, direction, unit, 1, mode, description, &typeid(ChimeraTK::Void), tags) {}
+
+  /********************************************************************************************************************/
 
 } /* namespace ChimeraTK */
diff --git a/include/XMLGeneratorVisitor.h b/include/XMLGeneratorVisitor.h
index 93842533..e537fdce 100644
--- a/include/XMLGeneratorVisitor.h
+++ b/include/XMLGeneratorVisitor.h
@@ -14,10 +14,14 @@ namespace xmlpp {
 } // namespace xmlpp
 
 namespace ChimeraTK {
+
+  /********************************************************************************************************************/
   // Forward declarations
   class Application;
   class VariableNetworkNode;
 
+  /********************************************************************************************************************/
+
   /**
    * @brief The XMLGeneratorVisitor class
    *
@@ -38,4 +42,6 @@ namespace ChimeraTK {
     xmlpp::Element* _rootElement;
   };
 
+  /********************************************************************************************************************/
+
 } // namespace ChimeraTK
diff --git a/src/Application.cc b/src/Application.cc
index 6a084871..db59d600 100644
--- a/src/Application.cc
+++ b/src/Application.cc
@@ -61,6 +61,48 @@ void Application::defineConnections() {
 
 /*********************************************************************************************************************/
 
+void Application::enableTestableMode() {
+  threadName() = "TEST THREAD";
+  testableMode = true;
+  testableModeLock("enableTestableMode");
+}
+
+/*********************************************************************************************************************/
+
+bool Application::testableModeTestLock() {
+  if(!getInstance().testableMode) return false;
+  return getTestableModeLockObject().owns_lock();
+}
+
+/*********************************************************************************************************************/
+
+void Application::registerThread(const std::string& name) {
+  Application::getInstance().setThreadName(name);
+  Profiler::registerThread(name);
+  pthread_setname_np(pthread_self(), name.substr(0, std::min<std::string::size_type>(name.length(), 15)).c_str());
+}
+
+/*********************************************************************************************************************/
+
+void Application::incrementDataLossCounter(const std::string& name) {
+  if(getInstance().debugDataLoss) {
+    std::cout << "Data loss in variable " << name << std::endl;
+  }
+  getInstance().dataLossCounter++;
+}
+
+/*********************************************************************************************************************/
+
+size_t Application::getAndResetDataLossCounter() {
+  size_t counter = getInstance().dataLossCounter.load(std::memory_order_relaxed);
+  while(!getInstance().dataLossCounter.compare_exchange_weak(
+      counter, 0, std::memory_order_release, std::memory_order_relaxed)) {
+  }
+  return counter;
+}
+
+/*********************************************************************************************************************/
+
 void Application::initialise() {
   if(initialiseCalled) {
     throw ChimeraTK::logic_error("Application::initialise() was already called before.");
diff --git a/src/ApplicationModule.cc b/src/ApplicationModule.cc
index 53a8021e..06a9a8d3 100644
--- a/src/ApplicationModule.cc
+++ b/src/ApplicationModule.cc
@@ -41,6 +41,15 @@ namespace ChimeraTK {
 
   /*********************************************************************************************************************/
 
+  ApplicationModule& ApplicationModule::operator=(ApplicationModule&& other) {
+    assert(!moduleThread.joinable()); // if the thread is already running,
+                                      // moving is no longer allowed!
+    ModuleImpl::operator=(std::move(other));
+    return *this;
+  }
+
+  /*********************************************************************************************************************/
+
   void ApplicationModule::run() {
     // start the module thread
     assert(!moduleThread.joinable());
@@ -77,6 +86,12 @@ namespace ChimeraTK {
 
   /*********************************************************************************************************************/
 
+  void ApplicationModule::setCurrentVersionNumber(VersionNumber versionNumber) {
+    if(versionNumber > currentVersionNumber) currentVersionNumber = versionNumber;
+  }
+
+  /*********************************************************************************************************************/
+
   void ApplicationModule::mainLoopWrapper() {
     Application::registerThread("AM_" + getName());
 
diff --git a/src/ControlSystemModule.cc b/src/ControlSystemModule.cc
index c8b8af4f..9c4c9bc6 100644
--- a/src/ControlSystemModule.cc
+++ b/src/ControlSystemModule.cc
@@ -19,6 +19,15 @@ namespace ChimeraTK {
 
   /*********************************************************************************************************************/
 
+  ControlSystemModule& ControlSystemModule::operator=(ControlSystemModule&& other) {
+    Module::operator=(std::move(other));
+    variableNamePrefix = std::move(other.variableNamePrefix);
+    subModules = std::move(other.subModules);
+    return *this;
+  }
+
+  /********************************************************************************************************************/
+
   VariableNetworkNode ControlSystemModule::operator()(
       const std::string& variableName, const std::type_info& valueType, size_t nElements) const {
     assert(variableName.find_first_of("/") == std::string::npos);
diff --git a/src/DebugPrintAccessorDecorator.cc b/src/DebugPrintAccessorDecorator.cc
new file mode 100644
index 00000000..47e18c69
--- /dev/null
+++ b/src/DebugPrintAccessorDecorator.cc
@@ -0,0 +1,89 @@
+// SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
+// SPDX-License-Identifier: LGPL-3.0-or-later
+
+#include "DebugPrintAccessorDecorator.h"
+
+namespace ChimeraTK {
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  DebugPrintAccessorDecorator<UserType>::DebugPrintAccessorDecorator(
+      boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> accessor, const std::string& fullyQualifiedName)
+  : ChimeraTK::NDRegisterAccessorDecorator<UserType>(accessor), _fullyQualifiedName(fullyQualifiedName) {
+    std::cout << "Enable debug output for variable '" << _fullyQualifiedName << "'." << std::endl;
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  bool DebugPrintAccessorDecorator<UserType>::doWriteTransfer(ChimeraTK::VersionNumber versionNumber) {
+    std::cout << "doWriteTransfer() called on '" << _fullyQualifiedName << "'." << std::flush;
+    auto ret = ChimeraTK::NDRegisterAccessorDecorator<UserType>::doWriteTransfer(versionNumber);
+    if(ret) {
+      std::cout << " -> DATA LOSS!";
+    }
+    std::cout << std::endl;
+    return ret;
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  bool DebugPrintAccessorDecorator<UserType>::doWriteTransferDestructively(ChimeraTK::VersionNumber versionNumber) {
+    std::cout << "doWriteTransferDestructively() called on '" << _fullyQualifiedName << "'." << std::flush;
+    auto ret = ChimeraTK::NDRegisterAccessorDecorator<UserType>::doWriteTransferDestructively(versionNumber);
+    if(ret) {
+      std::cout << " -> DATA LOSS!";
+    }
+    std::cout << std::endl;
+    return ret;
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  void DebugPrintAccessorDecorator<UserType>::doReadTransferSynchronously() {
+    std::cout << "doReadTransferSynchronously() called on '" << _fullyQualifiedName << "'." << std::endl;
+    ChimeraTK::NDRegisterAccessorDecorator<UserType>::doReadTransferSynchronously();
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  void DebugPrintAccessorDecorator<UserType>::doPreRead(TransferType type) {
+    std::cout << "preRead() called on '" << _fullyQualifiedName << "'." << std::endl;
+    ChimeraTK::NDRegisterAccessorDecorator<UserType>::doPreRead(type);
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  void DebugPrintAccessorDecorator<UserType>::doPostRead(TransferType type, bool hasNewData) {
+    std::cout << "postRead() called on '" << _fullyQualifiedName << "'." << std::endl;
+    ChimeraTK::NDRegisterAccessorDecorator<UserType>::doPostRead(type, hasNewData);
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  void DebugPrintAccessorDecorator<UserType>::doPreWrite(TransferType type, VersionNumber versionNumber) {
+    std::cout << "preWrite() called on '" << _fullyQualifiedName << "'." << std::endl;
+    ChimeraTK::NDRegisterAccessorDecorator<UserType>::doPreWrite(type, versionNumber);
+  }
+
+  /********************************************************************************************************************/
+
+  template<typename UserType>
+  void DebugPrintAccessorDecorator<UserType>::doPostWrite(TransferType type, VersionNumber versionNumber) {
+    std::cout << "postWrite() called on '" << _fullyQualifiedName << "'." << std::endl;
+    ChimeraTK::NDRegisterAccessorDecorator<UserType>::doPostWrite(type, versionNumber);
+  }
+
+  /********************************************************************************************************************/
+
+  INSTANTIATE_TEMPLATE_FOR_CHIMERATK_USER_TYPES(DebugPrintAccessorDecorator);
+
+  /********************************************************************************************************************/
+
+} // namespace ChimeraTK
diff --git a/src/DeviceModule.cc b/src/DeviceModule.cc
index 1438bd36..38a9218b 100644
--- a/src/DeviceModule.cc
+++ b/src/DeviceModule.cc
@@ -76,6 +76,25 @@ namespace ChimeraTK {
 
   /*********************************************************************************************************************/
 
+  DeviceModule& DeviceModule::operator=(DeviceModule&& other) {
+    assert(!moduleThread.joinable());
+    assert(other.isHoldingInitialValueLatch);
+    if(owner) owner->unregisterDeviceModule(this);
+    Module::operator=(std::move(other));
+    device = std::move(other.device);
+    deviceAliasOrURI = std::move(other.deviceAliasOrURI);
+    registerNamePrefix = std::move(other.registerNamePrefix);
+    deviceError = std::move(other.deviceError);
+    owner = other.owner;
+    proxies = std::move(other.proxies);
+    deviceHasError = other.deviceHasError;
+    for(auto& proxy : proxies) proxy.second._myowner = this;
+    owner->registerDeviceModule(this);
+    return *this;
+  }
+
+  /*********************************************************************************************************************/
+
   VariableNetworkNode DeviceModule::operator()(
       const std::string& registerName, UpdateMode mode, const std::type_info& valueType, size_t nElements) const {
     return {registerName, deviceAliasOrURI, registerNamePrefix / registerName, mode,
@@ -84,6 +103,19 @@ namespace ChimeraTK {
 
   /*********************************************************************************************************************/
 
+  VariableNetworkNode DeviceModule::operator()(
+      const std::string& registerName, const std::type_info& valueType, size_t nElements, UpdateMode mode) const {
+    return operator()(registerName, mode, valueType, nElements);
+  }
+
+  /*********************************************************************************************************************/
+
+  VariableNetworkNode DeviceModule::operator()(const std::string& variableName) const {
+    return operator()(variableName, UpdateMode::poll);
+  }
+
+  /*********************************************************************************************************************/
+
   Module& DeviceModule::operator[](const std::string& moduleName) const {
     assert(moduleName.find_first_of("/") == std::string::npos);
     return getProxy(moduleName);
@@ -492,6 +524,12 @@ namespace ChimeraTK {
 
   /*********************************************************************************************************************/
 
+  void DeviceModule::setCurrentVersionNumber(VersionNumber versionNumber) {
+    if(versionNumber > currentVersionNumber) currentVersionNumber = versionNumber;
+  }
+
+  /*********************************************************************************************************************/
+
   void DeviceModule::defineConnections() {
     // replace all slashes in the deviceAliasOrURI, because URIs might contain slashes and they are not allowed in
     // module names
@@ -537,6 +575,35 @@ namespace ChimeraTK {
     initialValueLatch.wait();
   }
 
+  /*********************************************************************************************************************/
+
+  std::list<EntityOwner*> DeviceModule::getInputModulesRecursively(std::list<EntityOwner*> startList) {
+    // The DeviceModule is the end of the recursion, and is not considered recursive to itself.
+    // There will always be circular connections to the CS module which does not pose a problem.
+    // Just return the startList without adding anything (not even the DeviceModule itself)
+    return startList;
+  }
+
+  /*********************************************************************************************************************/
+
+  size_t DeviceModule::getCircularNetworkHash() {
+    return 0; // The device module is never part of a circular network
+  }
+
+  /*********************************************************************************************************************/
+
+  void DeviceModule::incrementDataFaultCounter() {
+    throw ChimeraTK::logic_error("incrementDataFaultCounter() called on a DeviceModule. This is probably "
+                                 "caused by incorrect ownership of variables/accessors or VariableGroups.");
+  }
+
+  /*********************************************************************************************************************/
+
+  void DeviceModule::decrementDataFaultCounter() {
+    throw ChimeraTK::logic_error("decrementDataFaultCounter() called on a DeviceModule. This is probably "
+                                 "caused by incorrect ownership of variables/accessors or VariableGroups.");
+  }
+
   /*********************************************************************************************************************/
   /*********************************************************************************************************************/
 
@@ -599,21 +666,4 @@ namespace ChimeraTK {
 
   /*********************************************************************************************************************/
 
-  std::list<EntityOwner*> DeviceModule::getInputModulesRecursively(std::list<EntityOwner*> startList) {
-    // The DeviceModule is the end of the recursion, and is not considered recursive to itself.
-    // There will always be circular connections to the CS module which does not pose a problem.
-    // Just return the startList without adding anything (not even the DeviceModule itself)
-    return startList;
-  }
-
-  /*********************************************************************************************************************/
-
-  size_t DeviceModule::getCircularNetworkHash() {
-    return 0; // The device module is never part of a circular network
-  }
-
-  /*********************************************************************************************************************/
-
-  /*********************************************************************************************************************/
-
 } // namespace ChimeraTK
diff --git a/src/EntityOwner.cc b/src/EntityOwner.cc
index 76a7996d..9290c76e 100644
--- a/src/EntityOwner.cc
+++ b/src/EntityOwner.cc
@@ -14,23 +14,31 @@
 
 namespace ChimeraTK {
 
+  /********************************************************************************************************************/
+
   EntityOwner::EntityOwner(const std::string& name, const std::string& description, bool eliminateHierarchy,
       const std::unordered_set<std::string>& tags)
   : _name(name), _description(description), _tags(tags) {
     if(eliminateHierarchy) _hierarchyModifier = HierarchyModifier::hideThis;
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   EntityOwner::EntityOwner(const std::string& name, const std::string& description, HierarchyModifier hierarchyModifier,
       const std::unordered_set<std::string>& tags)
   : _name(name), _description(description), _hierarchyModifier(hierarchyModifier), _tags(tags) {}
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
+
+  EntityOwner::EntityOwner()
+  : _name("**INVALID**"), _description("Invalid EntityOwner created by default constructor just "
+                                       "as a place holder") {}
+
+  /********************************************************************************************************************/
 
   EntityOwner::~EntityOwner() {}
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   EntityOwner& EntityOwner::operator=(EntityOwner&& other) {
     _name = std::move(other._name);
@@ -48,7 +56,7 @@ namespace ChimeraTK {
     return *this;
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   void EntityOwner::registerModule(Module* module, bool addTags) {
     if(addTags)
@@ -56,13 +64,13 @@ namespace ChimeraTK {
     moduleList.push_back(module);
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   void EntityOwner::unregisterModule(Module* module) {
     moduleList.remove(module);
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   std::list<VariableNetworkNode> EntityOwner::getAccessorListRecursive() const {
     // add accessors of this instance itself
@@ -76,7 +84,7 @@ namespace ChimeraTK {
     return list;
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   std::list<Module*> EntityOwner::getSubmoduleListRecursive() const {
     // add modules of this instance itself
@@ -90,14 +98,14 @@ namespace ChimeraTK {
     return list;
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   bool EntityOwner::getEliminateHierarchy() const {
     return (_hierarchyModifier == HierarchyModifier::hideThis) ||
         (_hierarchyModifier == HierarchyModifier::oneUpAndHide);
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   VirtualModule EntityOwner::findTag(const std::string& tag) const {
     // create new module to return
@@ -120,7 +128,7 @@ namespace ChimeraTK {
     return module;
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   VirtualModule EntityOwner::excludeTag(const std::string& tag) const {
     // create new module to return
@@ -143,7 +151,14 @@ namespace ChimeraTK {
     return module;
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
+
+  void EntityOwner::registerAccessor(VariableNetworkNode accessor) {
+    for(auto& tag : _tags) accessor.addTag(tag);
+    accessorList.push_back(accessor);
+  }
+
+  /********************************************************************************************************************/
 
   // The function adds virtual versions of the EntityOwner itself anf all its children to a virtual module (parent).
   void EntityOwner::findTagAndAppendToModule(VirtualModule& virtualParent, const std::string& tag,
@@ -221,7 +236,7 @@ namespace ChimeraTK {
     }
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   bool EntityOwner::hasSubmodule(const std::string& name) const {
     for(auto submodule : getSubmoduleList()) {
@@ -230,7 +245,7 @@ namespace ChimeraTK {
     return false;
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   Module* EntityOwner::getSubmodule(const std::string& name) const {
     for(auto submodule : getSubmoduleList()) {
@@ -239,7 +254,7 @@ namespace ChimeraTK {
     throw ChimeraTK::logic_error("Submodule '" + name + "' not found in module '" + getName() + "'!");
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   void EntityOwner::dump(const std::string& prefix) const {
     if(prefix == "") {
@@ -257,7 +272,7 @@ namespace ChimeraTK {
     }
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   void EntityOwner::dumpGraph(const std::string& fileName) const {
     std::fstream file(fileName, std::ios_base::out);
@@ -265,7 +280,7 @@ namespace ChimeraTK {
     v.dispatch(*this);
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   void EntityOwner::dumpModuleGraph(const std::string& fileName) const {
     std::fstream file(fileName, std::ios_base::out);
@@ -273,7 +288,7 @@ namespace ChimeraTK {
     v.dispatch(*this);
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   void EntityOwner::addTag(const std::string& tag) {
     for(auto& node : getAccessorList()) node.addTag(tag);
@@ -281,7 +296,7 @@ namespace ChimeraTK {
     _tags.insert(tag);
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   VirtualModule EntityOwner::flatten() {
     VirtualModule nextmodule{_name, _description, getModuleType()};
@@ -291,12 +306,12 @@ namespace ChimeraTK {
     return nextmodule;
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   bool EntityOwner::hasReachedTestableMode() {
     return testableModeReached;
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
 } /* namespace ChimeraTK */
diff --git a/src/Module.cc b/src/Module.cc
index c84b9aa8..0c8bce7e 100644
--- a/src/Module.cc
+++ b/src/Module.cc
@@ -258,4 +258,26 @@ namespace ChimeraTK {
 
   /*********************************************************************************************************************/
 
+  std::string Module::getQualifiedName() const {
+    return ((_owner != nullptr) ? _owner->getQualifiedName() : "") + "/" + _name;
+  }
+
+  /*********************************************************************************************************************/
+
+  std::string Module::getFullDescription() const {
+    if(_owner == nullptr) return _description;
+    auto ownerDescription = _owner->getFullDescription();
+    if(ownerDescription == "") return _description;
+    if(_description == "") return ownerDescription;
+    return ownerDescription + " - " + _description;
+  }
+
+  /*********************************************************************************************************************/
+
+  std::list<EntityOwner*> Module::getInputModulesRecursively(std::list<EntityOwner*> startList) {
+    return _owner->getInputModulesRecursively(startList);
+  }
+
+  /*********************************************************************************************************************/
+
 } /* namespace ChimeraTK */
diff --git a/src/ModuleGroup.cc b/src/ModuleGroup.cc
index c63adbcc..a99a29ed 100644
--- a/src/ModuleGroup.cc
+++ b/src/ModuleGroup.cc
@@ -6,6 +6,8 @@
 
 namespace ChimeraTK {
 
+  /********************************************************************************************************************/
+
   ModuleGroup::ModuleGroup(EntityOwner* owner, const std::string& name, const std::string& description,
       HierarchyModifier hierarchyModifier, const std::unordered_set<std::string>& tags)
   : ModuleImpl(owner, name, description, hierarchyModifier, tags) {
@@ -15,6 +17,8 @@ namespace ChimeraTK {
     }
   }
 
+  /********************************************************************************************************************/
+
   ModuleGroup::ModuleGroup(EntityOwner* owner, const std::string& name, const std::string& description,
       bool eliminateHierarchy, const std::unordered_set<std::string>& tags)
   : ModuleImpl(owner, name, description, eliminateHierarchy, tags) {
@@ -24,4 +28,13 @@ namespace ChimeraTK {
     }
   }
 
+  /********************************************************************************************************************/
+
+  ModuleGroup& ModuleGroup::operator=(ModuleGroup&& other) {
+    ModuleImpl::operator=(std::move(other));
+    return *this;
+  }
+
+  /********************************************************************************************************************/
+
 } /* namespace ChimeraTK */
diff --git a/src/ModuleImpl.cc b/src/ModuleImpl.cc
index 52143041..458e4b7e 100644
--- a/src/ModuleImpl.cc
+++ b/src/ModuleImpl.cc
@@ -9,6 +9,27 @@ namespace ChimeraTK {
 
   /*********************************************************************************************************************/
 
+  ModuleImpl::ModuleImpl(EntityOwner* owner, const std::string& name, const std::string& description,
+      HierarchyModifier hierarchyModifier, const std::unordered_set<std::string>& tags)
+  : Module(owner, name, description, hierarchyModifier, tags) {}
+
+  /*********************************************************************************************************************/
+
+  ModuleImpl::ModuleImpl(EntityOwner* owner, const std::string& name, const std::string& description,
+      bool eliminateHierarchy, const std::unordered_set<std::string>& tags)
+  : Module(owner, name, description, eliminateHierarchy, tags) {}
+
+  /*********************************************************************************************************************/
+
+  ModuleImpl& ModuleImpl::operator=(ModuleImpl&& other) {
+    if(other.virtualisedModule_isValid) virtualisedModule = other.virtualisedModule;
+    virtualisedModule_isValid = other.virtualisedModule_isValid;
+    Module::operator=(std::forward<ModuleImpl>(other));
+    return *this;
+  }
+
+  /*********************************************************************************************************************/
+
   VariableNetworkNode ModuleImpl::operator()(const std::string& variableName) const {
     return virtualise()(variableName);
   }
diff --git a/src/TestFacility.cc b/src/TestFacility.cc
new file mode 100644
index 00000000..dd61df0c
--- /dev/null
+++ b/src/TestFacility.cc
@@ -0,0 +1,131 @@
+// SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
+// SPDX-License-Identifier: LGPL-3.0-or-later
+
+#include "TestFacility.h"
+
+namespace ChimeraTK {
+
+  /********************************************************************************************************************/
+
+  TestFacility::TestFacility(bool enableTestableMode) {
+    auto pvManagers = createPVManager();
+    pvManager = pvManagers.first;
+    Application::getInstance().setPVManager(pvManagers.second);
+    if(enableTestableMode) Application::getInstance().enableTestableMode();
+    Application::getInstance().initialise();
+  }
+
+  /********************************************************************************************************************/
+
+  void TestFacility::runApplication() const {
+    Application::getInstance().testFacilityRunApplicationCalled = true;
+    // send default values for all control system variables
+    for(auto& pv : pvManager->getAllProcessVariables()) {
+      callForTypeNoVoid(pv->getValueType(), [&pv, this](auto arg) {
+        // Applies only to writeable variables. @todo FIXME It should also NOT apply for application-to-controlsystem
+        // variables with a return channel, despite being writeable here!
+        if(!pv->isWriteable()) return;
+        // Safety check against incorrect usage
+        if(pv->getVersionNumber() != VersionNumber(nullptr)) {
+          throw ChimeraTK::logic_error("The variable '" + pv->getName() +
+              "' has been written before TestFacility::runApplication() was called. Instead use "
+              "TestFacility::setScalarDefault() resp. setArrayDefault() to set initial values.");
+        }
+        typedef decltype(arg) T;
+        auto pv_casted = boost::dynamic_pointer_cast<NDRegisterAccessor<T>>(pv);
+        auto table = boost::fusion::at_key<T>(defaults.table);
+        // If default value has been stored, copy the default value to the PV.
+        if(table.find(pv->getName()) != table.end()) {
+          /// Since pv_casted is the undecorated PV (lacking the TestableModeAccessorDecorator), we need to copy the
+          /// value also to the decorator. We still have to write through the undecorated PV, otherwise the tests are
+          /// stalled. @todo It is not understood why this happens!
+          /// Decorated accessors are stored in different maps for scalars are arrays...
+          if(pv_casted->getNumberOfSamples() == 1) { // scalar
+            auto accessor = this->getScalar<T>(pv->getName());
+            accessor = table.at(pv->getName())[0];
+          }
+          else { // array
+            auto accessor = this->getArray<T>(pv->getName());
+            accessor = table.at(pv->getName());
+          }
+          // copy value also to undecorated PV
+          pv_casted->accessChannel(0) = table.at(pv->getName());
+        }
+        // Write the initial value. This must be done even if no default value has been stored, since it is expected
+        // by the application.
+        pv_casted->write();
+      });
+    }
+    // start the application
+    Application::getInstance().run();
+    // set thread name
+    Application::registerThread("TestThread");
+    // make sure all initial values have been propagated when in testable mode
+    if(Application::getInstance().isTestableModeEnabled()) {
+      // call stepApplication() only in testable mode and only if the queues are not empty
+      if(Application::getInstance().testableMode_counter != 0 ||
+          Application::getInstance().testableMode_deviceInitialisationCounter != 0) {
+        stepApplication();
+      }
+    }
+
+    // receive all initial values for the control system variables
+    if(Application::getInstance().isTestableModeEnabled()) {
+      for(auto& pv : pvManager->getAllProcessVariables()) {
+        if(!pv->isReadable()) continue;
+        callForTypeNoVoid(pv->getValueType(), [&](auto t) {
+          typedef decltype(t) UserType;
+          this->getArray<UserType>(pv->getName()).readNonBlocking();
+        });
+      }
+    }
+  }
+
+  /********************************************************************************************************************/
+
+  bool TestFacility::canStepApplication() const {
+    return Application::getInstance().canStepApplication();
+  }
+
+  /********************************************************************************************************************/
+
+  void TestFacility::stepApplication(bool waitForDeviceInitialisation) const {
+    Application::getInstance().stepApplication(waitForDeviceInitialisation);
+  }
+
+  /********************************************************************************************************************/
+
+  ChimeraTK::VoidRegisterAccessor TestFacility::getVoid(const ChimeraTK::RegisterPath& name) const {
+    // check for existing accessor in cache
+    if(boost::fusion::at_key<ChimeraTK::Void>(accessorMap.table).count(name) > 0) {
+      return boost::fusion::at_key<ChimeraTK::Void>(accessorMap.table)[name];
+    }
+
+    // obtain accessor from ControlSystemPVManager
+    auto pv = pvManager->getProcessArray<ChimeraTK::Void>(name);
+    if(pv == nullptr) {
+      throw ChimeraTK::logic_error("Process variable '" + name + "' does not exist.");
+    }
+
+    // obtain variable id from pvIdMap and transfer it to idMap (required by the
+    // TestableModeAccessorDecorator)
+    size_t varId = Application::getInstance().pvIdMap[pv->getUniqueId()];
+
+    // decorate with TestableModeAccessorDecorator if variable is sender and
+    // receiver is not poll-type, and store it in cache
+    if(pv->isWriteable() && !Application::getInstance().testableMode_isPollMode[varId]) {
+      auto deco = boost::make_shared<TestableModeAccessorDecorator<ChimeraTK::Void>>(pv, false, true, varId, varId);
+      Application::getInstance().testableMode_names[varId] = "ControlSystem:" + name;
+      boost::fusion::at_key<ChimeraTK::Void>(accessorMap.table)[name] = deco;
+    }
+    else {
+      boost::fusion::at_key<ChimeraTK::Void>(accessorMap.table)[name] = pv;
+    }
+
+    // return the accessor as stored in the cache
+    return boost::fusion::at_key<ChimeraTK::Void>(accessorMap.table)[name];
+  }
+
+  /********************************************************************************************************************/
+
+} // namespace ChimeraTK
diff --git a/src/TriggerFanOut.cc b/src/TriggerFanOut.cc
new file mode 100644
index 00000000..b46ac704
--- /dev/null
+++ b/src/TriggerFanOut.cc
@@ -0,0 +1,116 @@
+// SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
+// SPDX-License-Identifier: LGPL-3.0-or-later
+
+#include "TriggerFanOut.h"
+
+namespace ChimeraTK {
+
+  /********************************************************************************************************************/
+
+  TriggerFanOut::TriggerFanOut(const boost::shared_ptr<ChimeraTK::TransferElement>& externalTriggerImpl,
+      DeviceModule& deviceModule, VariableNetwork& network)
+  : externalTrigger(externalTriggerImpl), _deviceModule(deviceModule), _network(network) {}
+
+  /********************************************************************************************************************/
+
+  TriggerFanOut::~TriggerFanOut() {
+    deactivate();
+  }
+
+  /********************************************************************************************************************/
+
+  void TriggerFanOut::activate() {
+    assert(!_thread.joinable());
+    _thread = boost::thread([this] { this->run(); });
+  }
+
+  /********************************************************************************************************************/
+
+  void TriggerFanOut::deactivate() {
+    if(_thread.joinable()) {
+      _thread.interrupt();
+      if(externalTrigger->getAccessModeFlags().has(AccessMode::wait_for_new_data)) {
+        externalTrigger->interrupt();
+      }
+      _thread.join();
+    }
+    assert(!_thread.joinable());
+  }
+
+  /********************************************************************************************************************/
+
+  namespace {
+    struct SendDataToConsumers {
+      SendDataToConsumers(VersionNumber version, DataValidity triggerValidity)
+      : _version(version), _triggerValidity(triggerValidity) {}
+
+      template<typename PAIR>
+      void operator()(PAIR& pair) const {
+        auto theMap = pair.second; // map of feeder to FeedingFanOut (i.e. part of
+                                   // the fanOutMap)
+
+        // iterate over all feeder/FeedingFanOut pairs
+        for(auto& network : theMap) {
+          auto feeder = network.first;
+          auto fanOut = network.second;
+          fanOut->setDataValidity((_triggerValidity == DataValidity::ok && feeder->dataValidity() == DataValidity::ok) ?
+                  DataValidity::ok :
+                  DataValidity::faulty);
+          fanOut->accessChannel(0).swap(feeder->accessChannel(0));
+          // don't use write destructively. In case of an exception we still need the data for the next read (see
+          // Exception Handling spec B.2.2.6)
+          bool dataLoss = fanOut->write(_version);
+          if(dataLoss) Application::incrementDataLossCounter(fanOut->getName());
+          // swap the data back to the feeder so we have a valid copy there.
+          fanOut->accessChannel(0).swap(feeder->accessChannel(0));
+        }
+      }
+
+      VersionNumber _version;
+      DataValidity _triggerValidity;
+    };
+  } // namespace
+
+  /********************************************************************************************************************/
+
+  void TriggerFanOut::run() {
+    Application::registerThread("TrFO" + externalTrigger->getName());
+    Application::testableModeLock("start");
+    testableModeReached = true;
+
+    ChimeraTK::VersionNumber version = Application::getInstance().getStartVersion();
+
+    // Wait for the initial value of the trigger. There always will be one, and if we don't read it here we would
+    // trigger the loop twice.
+    externalTrigger->read();
+    version = externalTrigger->getVersionNumber();
+
+    // Wait until the device has been initialised for the first time. This means it
+    // has been opened, and the check in TransferGroup::read() will not throw a logic_error
+    // We don't have to store the lock. Just need it as a synchronisation point.
+    // But we have to increase the testable mode counter because we don't want to fall out of testable mode at this
+    // point already.
+    if(Application::getInstance().testableMode) ++Application::getInstance().testableMode_deviceInitialisationCounter;
+    Application::testableModeUnlock("WaitInitialValueLock");
+    (void)_deviceModule.waitForInitialValues();
+    Application::testableModeLock("Enter while loop");
+    if(Application::getInstance().testableMode) --Application::getInstance().testableMode_deviceInitialisationCounter;
+
+    while(true) {
+      transferGroup.read();
+      // send the version number to the consumers
+      boost::fusion::for_each(fanOutMap.table, SendDataToConsumers(version, externalTrigger->dataValidity()));
+
+      // wait for external trigger
+      boost::this_thread::interruption_point();
+      Profiler::stopMeasurement();
+      externalTrigger->read();
+      Profiler::startMeasurement();
+      boost::this_thread::interruption_point();
+      version = externalTrigger->getVersionNumber();
+    }
+  }
+
+  /********************************************************************************************************************/
+
+} // namespace ChimeraTK
diff --git a/src/VariableGroup.cc b/src/VariableGroup.cc
index 6ac9b255..87243396 100644
--- a/src/VariableGroup.cc
+++ b/src/VariableGroup.cc
@@ -7,6 +7,8 @@
 
 namespace ChimeraTK {
 
+  /********************************************************************************************************************/
+
   VariableGroup::VariableGroup(EntityOwner* owner, const std::string& name, const std::string& description,
       HierarchyModifier hierarchyModifier, const std::unordered_set<std::string>& tags)
   : ModuleImpl(owner, name, description, hierarchyModifier, tags) {
@@ -17,6 +19,8 @@ namespace ChimeraTK {
     }
   }
 
+  /********************************************************************************************************************/
+
   VariableGroup::VariableGroup(EntityOwner* owner, const std::string& name, const std::string& description,
       bool eliminateHierarchy, const std::unordered_set<std::string>& tags)
   : ModuleImpl(owner, name, description, eliminateHierarchy, tags) {
@@ -27,4 +31,13 @@ namespace ChimeraTK {
     }
   }
 
+  /********************************************************************************************************************/
+
+  VariableGroup& VariableGroup::operator=(VariableGroup&& other) {
+    ModuleImpl::operator=(std::move(other));
+    return *this;
+  }
+
+  /********************************************************************************************************************/
+
 } /* namespace ChimeraTK */
diff --git a/src/VariableNetwork.cc b/src/VariableNetwork.cc
index 6d36ac44..917e0b4f 100644
--- a/src/VariableNetwork.cc
+++ b/src/VariableNetwork.cc
@@ -339,4 +339,15 @@ namespace ChimeraTK {
 
     return true;
   }
+
+  /*********************************************************************************************************************/
+
+  bool VariableNetwork::operator==(const VariableNetwork& other) const {
+    if(other.valueType != valueType) return false;
+    if(other.nodeList != nodeList) return false;
+    return true;
+  }
+
+  /*********************************************************************************************************************/
+
 } // namespace ChimeraTK
diff --git a/src/VariableNetworkDumpingVisitor.cc b/src/VariableNetworkDumpingVisitor.cc
index cdd17208..8b0f77a6 100644
--- a/src/VariableNetworkDumpingVisitor.cc
+++ b/src/VariableNetworkDumpingVisitor.cc
@@ -6,9 +6,13 @@
 
 namespace ChimeraTK {
 
+  /*********************************************************************************************************************/
+
   VariableNetworkDumpingVisitor::VariableNetworkDumpingVisitor(const std::string& prefix, std::ostream& stream)
   : Visitor<ChimeraTK::VariableNetwork>(), VariableNetworkNodeDumpingVisitor(stream, " "), _prefix(prefix) {}
 
+  /*********************************************************************************************************************/
+
   void VariableNetworkDumpingVisitor::dispatch(const VariableNetwork& t) {
     stream() << _prefix << "VariableNetwork";
     stream() << " {" << std::endl;
@@ -49,4 +53,6 @@ namespace ChimeraTK {
     stream() << _prefix << "}" << std::endl;
   }
 
+  /*********************************************************************************************************************/
+
 } // namespace ChimeraTK
diff --git a/src/VariableNetworkGraphDumpingVisitor.cc b/src/VariableNetworkGraphDumpingVisitor.cc
index 3b34ce5c..12079281 100644
--- a/src/VariableNetworkGraphDumpingVisitor.cc
+++ b/src/VariableNetworkGraphDumpingVisitor.cc
@@ -12,6 +12,8 @@
 
 namespace ChimeraTK {
 
+  /*********************************************************************************************************************/
+
   void VariableNetworkGraphDumpingVisitor::dispatch(const VariableNetwork& network) {
     std::string networkPrefix = "network_" + std::to_string(_networkCount++);
     pushPrefix(networkPrefix);
@@ -101,10 +103,14 @@ namespace ChimeraTK {
     popPrefix();
   }
 
+  /*********************************************************************************************************************/
+
   VariableNetworkGraphDumpingVisitor::VariableNetworkGraphDumpingVisitor(std::ostream& stream)
   : Visitor<Application, VariableNetwork>(), VariableNetworkNodeDumpingVisitor(stream, "\\n"), _triggerMap(),
     _triggerConnections(), _networkCount(0), _triggerCount(0) {}
 
+  /*********************************************************************************************************************/
+
   void VariableNetworkGraphDumpingVisitor::dispatch(const Application& t) {
     stream() << "digraph application {\n"
              //<< "  rankdir = LR;\n"
@@ -136,6 +142,8 @@ namespace ChimeraTK {
     stream() << "}\n";
   }
 
+  /*********************************************************************************************************************/
+
   void VariableNetworkGraphDumpingVisitor::dispatch(const VariableNetworkNode& t) {
     std::string nodeName = prefix() + detail::encodeDotNodeName(detail::nodeName(t));
     stream() << nodeName << "[\n";
@@ -153,4 +161,7 @@ namespace ChimeraTK {
 
     stream() << "\"]\n";
   }
+
+  /*********************************************************************************************************************/
+
 } // namespace ChimeraTK
diff --git a/src/VariableNetworkNodeDumpingVisitor.cc b/src/VariableNetworkNodeDumpingVisitor.cc
index 4049dad5..e409cd0b 100644
--- a/src/VariableNetworkNodeDumpingVisitor.cc
+++ b/src/VariableNetworkNodeDumpingVisitor.cc
@@ -6,10 +6,14 @@
 
 namespace ChimeraTK {
 
+  /********************************************************************************************************************/
+
   VariableNetworkNodeDumpingVisitor::VariableNetworkNodeDumpingVisitor(
       std::ostream& stream, const std::string& separator)
   : Visitor<ChimeraTK::VariableNetworkNode>(), PushableStream(stream), _separator(separator) {}
 
+  /********************************************************************************************************************/
+
   void VariableNetworkNodeDumpingVisitor::dispatch(const VariableNetworkNode& t) {
     if(t.getType() == NodeType::Application) stream() << " type = Application ('" << t.getQualifiedName() << "')";
     if(t.getType() == NodeType::ControlSystem) stream() << " type = ControlSystem ('" << t.getPublicName() << "')";
@@ -50,4 +54,6 @@ namespace ChimeraTK {
     stream() << std::endl;
   }
 
+  /********************************************************************************************************************/
+
 } // namespace ChimeraTK
diff --git a/src/VirtualModule.cc b/src/VirtualModule.cc
index b456e28d..fb8ef540 100644
--- a/src/VirtualModule.cc
+++ b/src/VirtualModule.cc
@@ -9,6 +9,17 @@
 
 namespace ChimeraTK {
 
+  /********************************************************************************************************************/
+
+  VirtualModule::VirtualModule(const std::string& name, const std::string& description, ModuleType moduleType)
+  : Module(nullptr, name, description), _moduleType(moduleType) {
+    if(name.find_first_of("/") != std::string::npos) {
+      throw ChimeraTK::logic_error("Module names must not contain slashes: '" + name + "'.");
+    }
+  }
+
+  /********************************************************************************************************************/
+
   VirtualModule::VirtualModule(const VirtualModule& other) : Module(nullptr, other.getName(), other.getDescription()) {
     // since moduleList stores plain pointers, we need to regenerate this list
     for(auto& mod : other.submodules) addSubModule(mod); // this creates a copy (call by value)
@@ -17,14 +28,14 @@ namespace ChimeraTK {
     _moduleType = other.getModuleType();
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   VirtualModule::~VirtualModule() {
     // do not unregister owner in Module destructor
     _owner = nullptr;
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   VirtualModule& VirtualModule::operator=(const VirtualModule& other) {
     // move-assign a plain new module
@@ -36,7 +47,7 @@ namespace ChimeraTK {
     return *this;
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   VariableNetworkNode VirtualModule::operator()(const std::string& variableName) const {
     for(auto& variable : getAccessorList()) {
@@ -45,7 +56,7 @@ namespace ChimeraTK {
     throw ChimeraTK::logic_error("Variable '" + variableName + "' is not part of the variable group '" + _name + "'.");
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   Module& VirtualModule::operator[](const std::string& moduleName) const {
     for(auto submodule : getSubmoduleList()) {
@@ -54,7 +65,7 @@ namespace ChimeraTK {
     throw ChimeraTK::logic_error("Sub-module '" + moduleName + "' is not part of the variable group '" + _name + "'.");
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   void VirtualModule::connectTo(const Module& target, VariableNetworkNode trigger) const {
     // connect all direct variables of this module to their counter-parts in the
@@ -88,13 +99,13 @@ namespace ChimeraTK {
     }
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   void VirtualModule::addAccessor(VariableNetworkNode accessor) {
     accessorList.push_back(accessor);
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   void VirtualModule::addSubModule(VirtualModule module) {
     if(!hasSubmodule(module.getName())) {
@@ -115,7 +126,7 @@ namespace ChimeraTK {
     }
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   void VirtualModule::removeSubModule(const std::string& name) {
     for(auto module = submodules.begin(); module != submodules.end(); ++module) {
@@ -127,13 +138,13 @@ namespace ChimeraTK {
     }
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   const Module& VirtualModule::virtualise() const {
     return *this;
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   VirtualModule& VirtualModule::createAndGetSubmodule(const RegisterPath& moduleName) {
     for(auto& sm : submodules) {
@@ -143,7 +154,7 @@ namespace ChimeraTK {
     return submodules.back();
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   VirtualModule& VirtualModule::createAndGetSubmoduleRecursive(const RegisterPath& moduleName) {
     if(moduleName == "") return *this;
@@ -158,7 +169,7 @@ namespace ChimeraTK {
     }
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
   void VirtualModule::stripEmptyChildsRecursive() {
     // first recurse into childs, to make sure to remove all we an
@@ -175,6 +186,6 @@ namespace ChimeraTK {
     }
   }
 
-  /*********************************************************************************************************************/
+  /********************************************************************************************************************/
 
 } /* namespace ChimeraTK */
diff --git a/src/VisitorHelper.cc b/src/VisitorHelper.cc
index 69f40514..95312655 100644
--- a/src/VisitorHelper.cc
+++ b/src/VisitorHelper.cc
@@ -6,6 +6,8 @@
 
 namespace ChimeraTK { namespace detail {
 
+  /********************************************************************************************************************/
+
   std::string encodeDotNodeName(std::string name) {
     std::replace(name.begin(), name.end(), '-', 'm'); // minus
     std::replace(name.begin(), name.end(), ':', 'c'); // colon
@@ -18,8 +20,12 @@ namespace ChimeraTK { namespace detail {
     return name;
   }
 
+  /********************************************************************************************************************/
+
   std::string nodeName(const VariableNetworkNode& node) {
     return node.getQualifiedName().empty() ? node.getName() : node.getQualifiedName();
   }
 
+  /********************************************************************************************************************/
+
 }} // namespace ChimeraTK::detail
diff --git a/src/XMLGeneratorVisitor.cc b/src/XMLGeneratorVisitor.cc
index 9a2c603c..76bf6ff4 100644
--- a/src/XMLGeneratorVisitor.cc
+++ b/src/XMLGeneratorVisitor.cc
@@ -13,14 +13,21 @@
 #include <cxxabi.h>
 
 namespace ChimeraTK {
+
+  /********************************************************************************************************************/
+
   XMLGeneratorVisitor::XMLGeneratorVisitor()
   : Visitor<ChimeraTK::Application, ChimeraTK::VariableNetworkNode>(), _doc(std::make_shared<xmlpp::Document>()),
     _rootElement(_doc->create_root_node("application", "https://github.com/ChimeraTK/ApplicationCore")) {}
 
+  /********************************************************************************************************************/
+
   void XMLGeneratorVisitor::save(const std::string& fileName) {
     _doc->write_to_file_formatted(fileName);
   }
 
+  /********************************************************************************************************************/
+
   void XMLGeneratorVisitor::dispatch(const Application& app) {
     _rootElement->set_attribute("name", app.getName());
     for(auto& network : app.networkList) {
@@ -35,6 +42,8 @@ namespace ChimeraTK {
     }
   }
 
+  /********************************************************************************************************************/
+
   void XMLGeneratorVisitor::dispatch(const VariableNetworkNode& node) {
     if(node.getType() != NodeType::ControlSystem) return;
 
@@ -201,4 +210,6 @@ namespace ChimeraTK {
     }
   }
 
+  /********************************************************************************************************************/
+
 } // namespace ChimeraTK
-- 
GitLab