10.12., 9:00 - 11:00: Due to updates GitLab may be unavailable for some minutes between 09:00 and 11:00.

Commit e95764be authored by Alessio Netti's avatar Alessio Netti

Analytics: refactoring of Analyzers to Operators

- Make clean might be required
parent 33252803
......@@ -4,7 +4,7 @@ include ../config.mk
CXXFLAGS += -DBOOST_NETWORK_ENABLE_HTTPS -I../common/include -I$(DCDBDEPLOYPATH)/include -I$(DCDBDEPLOYPATH)/include/opencv4
LIBS = -L../lib -L$(DCDBDEPLOYPATH)/lib/ -ldl -lboost_system -lboost_thread -lboost_log_setup -lboost_log -lboost_regex -lpthread -rdynamic
ANALYZERS = aggregator regressor job_aggregator testeranalyzer filesink smucngperfanalyzer
OPERATORS = aggregator regressor job_aggregator testeroperator filesink smucngperf
ifeq ($(OS),Darwin)
BACNET_PORT = bsd
......@@ -16,47 +16,47 @@ else
LIBFLAGS = -shared -Wl,-soname,
PLUGINFLAGS = -fPIC
endif
ANALYZER_LIBS = $(foreach p,$(ANALYZERS),libdcdbanalyzer_$(p).$(LIBEXT))
OPERATOR_LIBS = $(foreach p,$(OPERATORS),libdcdboperator_$(p).$(LIBEXT))
all: $(ANALYZER_LIBS)
all: $(OPERATOR_LIBS)
debug: CXXFLAGS += -DDEBUG
debug: all
clean:
rm -f $(ANALYZER_LIBS) $(shell find . -name "*.o")
rm -f $(OPERATOR_LIBS) $(shell find . -name "*.o")
rm -f ../common/src/sensornavigator.o
$(OBJS) : %.o : %.cpp
install_analyzer: $(ANALYZER_LIBS)
install_operator: $(OPERATOR_LIBS)
install $^ $(DCDBDEPLOYPATH)/lib/
install_conf: $(foreach p,$(ANALYZERS),config/$(p).conf)
install_conf: $(foreach p,$(OPERATORS),config/$(p).conf)
install -m 644 $^ $(DCDBDEPLOYPATH)/etc/
install: install_analyzer
install: install_operator
@echo "Done with installation."
@echo "====================================="
@echo "To copy the configuration files type:"
@echo " > make install_conf"
analyzers/%.o: CXXFLAGS+= $(PLUGINFLAGS)
operators/%.o: CXXFLAGS+= $(PLUGINFLAGS)
../common/src/sensornavigator.o: CXXFLAGS+= $(PLUGINFLAGS)
libdcdbanalyzer_aggregator.$(LIBEXT): analyzers/aggregator/AggregatorAnalyzer.o analyzers/aggregator/AggregatorConfigurator.o ../common/src/sensornavigator.o
libdcdboperator_aggregator.$(LIBEXT): operators/aggregator/AggregatorOperator.o operators/aggregator/AggregatorConfigurator.o ../common/src/sensornavigator.o
$(CXX) $(LIBFLAGS)$@ -o $@ $^ -L$(DCDBDEPLOYPATH)/lib/ -lboost_log -lboost_system -lboost_regex
libdcdbanalyzer_regressor.$(LIBEXT): analyzers/regressor/RegressorAnalyzer.o analyzers/regressor/RegressorConfigurator.o ../common/src/sensornavigator.o
libdcdboperator_regressor.$(LIBEXT): operators/regressor/RegressorOperator.o operators/regressor/RegressorConfigurator.o ../common/src/sensornavigator.o
$(CXX) $(LIBFLAGS)$@ -o $@ $^ -L$(DCDBDEPLOYPATH)/lib/ -lboost_log -lboost_system -lboost_regex -lopencv_core -lopencv_ml
libdcdbanalyzer_job_aggregator.$(LIBEXT): analyzers/aggregator/AggregatorAnalyzer.o analyzers/aggregator/JobAggregatorAnalyzer.o analyzers/aggregator/JobAggregatorConfigurator.o ../common/src/sensornavigator.o
libdcdboperator_job_aggregator.$(LIBEXT): operators/aggregator/AggregatorOperator.o operators/aggregator/JobAggregatorOperator.o operators/aggregator/JobAggregatorConfigurator.o ../common/src/sensornavigator.o
$(CXX) $(LIBFLAGS)$@ -o $@ $^ -L$(DCDBDEPLOYPATH)/lib/ -lboost_log -lboost_system -lboost_regex
libdcdbanalyzer_testeranalyzer.$(LIBEXT): analyzers/testeranalyzer/TesterAnalyzer.o analyzers/testeranalyzer/TesterAnalyzerConfigurator.o ../common/src/sensornavigator.o
libdcdboperator_testeroperator.$(LIBEXT): operators/testeroperator/TesterOperator.o operators/testeroperator/TesterOperatorConfigurator.o ../common/src/sensornavigator.o
$(CXX) $(LIBFLAGS)$@ -o $@ $^ -L$(DCDBDEPLOYPATH)/lib/ -lboost_log -lboost_system -lboost_regex
libdcdbanalyzer_filesink.$(LIBEXT): analyzers/filesink/FilesinkAnalyzer.o analyzers/filesink/FilesinkConfigurator.o ../common/src/sensornavigator.o
libdcdboperator_filesink.$(LIBEXT): operators/filesink/FilesinkOperator.o operators/filesink/FilesinkConfigurator.o ../common/src/sensornavigator.o
$(CXX) $(LIBFLAGS)$@ -o $@ $^ -L$(DCDBDEPLOYPATH)/lib/ -lboost_log -lboost_system -lboost_regex
libdcdbanalyzer_smucngperfanalyzer.$(LIBEXT): analyzers/smucngperfanalyzer/SMUCNGPerfAnalyzer.o analyzers/smucngperfanalyzer/SMUCNGPerfConfigurator.o ../common/src/sensornavigator.o
libdcdboperator_smucngperf.$(LIBEXT): operators/smucngperf/SMUCNGPerfOperator.o operators/smucngperf/SMUCNGPerfConfigurator.o ../common/src/sensornavigator.o
$(CXX) $(LIBFLAGS)$@ -o $@ $^ -L$(DCDBDEPLOYPATH)/lib/ -lboost_log -lboost_system -lboost_regex
This diff is collapsed.
......@@ -2,14 +2,14 @@ global {
mqttPrefix /test
}
template_analyzer def1 {
template_operator def1 {
interval 1000
minValues 3
duplicate false
streaming true
}
analyzer tes1 {
operator tes1 {
default def1
window 2000
relative false
......@@ -32,7 +32,7 @@ relative false
}
analyzer tes2 {
operator tes2 {
default def1
interval 1500
relative true
......
//================================================================================
// Name : JobAnalyzerConfiguratorTemplate.h
// Name : JobOperatorConfiguratorTemplate.h
// Author : Alessio Netti
// Contact : info@dcdb.it
// Copyright : Leibniz Supercomputing Centre
// Description : Template that implements a configurator for Job analyzer plugins.
// Description : Template that implements a configurator for Job operator plugins.
//================================================================================
//================================================================================
......@@ -25,99 +25,97 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//================================================================================
#ifndef PROJECT_JOBANALYZERCONFIGURATORTEMPLATE_H
#define PROJECT_JOBANALYZERCONFIGURATORTEMPLATE_H
#ifndef PROJECT_JOBOPERATORCONFIGURATORTEMPLATE_H
#define PROJECT_JOBOPERATORCONFIGURATORTEMPLATE_H
#include "AnalyzerConfiguratorTemplate.h"
#include "JobAnalyzerTemplate.h"
#include "OperatorConfiguratorTemplate.h"
#include "JobOperatorTemplate.h"
/**
* @brief Template that implements a configurator for Job analyzer plugins.
* @brief Template that implements a configurator for Job operator plugins.
*
* @details This template expands the standard AnalyzerConfiguratorTemplate,
* @details This template expands the standard OperatorConfiguratorTemplate,
* with very few changes to accomodate the different design of job
* analyzers.
* operators.
*
* @ingroup analyzer
* @ingroup operator
*/
template <class Analyzer, class SBase = SensorBase>
class JobAnalyzerConfiguratorTemplate : virtual public AnalyzerConfiguratorTemplate<Analyzer, SBase> {
template <class Operator, class SBase = SensorBase>
class JobOperatorConfiguratorTemplate : virtual public OperatorConfiguratorTemplate<Operator, SBase> {
// Verifying the types of input classes
static_assert(std::is_base_of<SensorBase, SBase>::value, "SBase must derive from SensorBase!");
static_assert(std::is_base_of<AnalyzerInterface, Analyzer>::value, "Analyzer must derive from AnalyzerInterface!");
static_assert(std::is_base_of<OperatorInterface, Operator>::value, "Operator must derive from OperatorInterface!");
protected:
// For readability
using A_Ptr = std::shared_ptr<Analyzer>;
using O_Ptr = std::shared_ptr<Operator>;
public:
/**
* @brief Class constructor
*/
JobAnalyzerConfiguratorTemplate() : AnalyzerConfiguratorTemplate<Analyzer, SBase>() {}
JobOperatorConfiguratorTemplate() : OperatorConfiguratorTemplate<Operator, SBase>() {}
/**
* @brief Copy constructor is not available
*/
JobAnalyzerConfiguratorTemplate(const JobAnalyzerConfiguratorTemplate&) = delete;
JobOperatorConfiguratorTemplate(const JobOperatorConfiguratorTemplate&) = delete;
/**
* @brief Assignment operator is not available
*/
JobAnalyzerConfiguratorTemplate& operator=(const JobAnalyzerConfiguratorTemplate&) = delete;
JobOperatorConfiguratorTemplate& operator=(const JobOperatorConfiguratorTemplate&) = delete;
/**
* @brief Class destructor
*/
virtual ~JobAnalyzerConfiguratorTemplate() {}
virtual ~JobOperatorConfiguratorTemplate() {}
protected:
/**
* @brief Instantiates all necessary units for a single (job) analyzer
* @brief Instantiates all necessary units for a single (job) operator
*
* When using job analyzers, the only unit that is always instantiated is ALWAYS the template
* unit, similarly to ordinary analyzers in on-demand mode. Such unit then is used at runtime,
* When using job operators, the only unit that is always instantiated is ALWAYS the template
* unit, similarly to ordinary operators in on-demand mode. Such unit then is used at runtime,
* even in streaming mode, to build dynamically all appropriate units for jobs that are
* currently running in the system.
*
* @param an The analyzer whose units must be created
* @param op The operator whose units must be created
* @param protoInputs The vector of prototype input sensors
* @param protoOutputs The vector of prototype output sensors
* @param inputMode Input mode to be used (selective, all or all_recursive)
* @return True if successful, false otherwise
*/
virtual bool readUnits(Analyzer& an, std::vector<shared_ptr<SBase>>& protoInputs, std::vector<shared_ptr<SBase>>& protoOutputs, inputMode_t inputMode) {
// Forcing the job analyzer to not be duplicated
an.setDuplicate(false);
virtual bool readUnits(Operator& op, std::vector<shared_ptr<SBase>>& protoInputs, std::vector<shared_ptr<SBase>>& protoOutputs, inputMode_t inputMode) {
// Forcing the job operator to not be duplicated
op.setDuplicate(false);
vector <shared_ptr<UnitTemplate<SBase>>> *units = NULL;
try {
units = this->_unitGen.generateUnits(protoInputs, protoOutputs, inputMode,
MQTTChecker::formatTopic(this->_mqttPrefix) + MQTTChecker::formatTopic(an.getMqttPart()),
true, an.getRelaxed());
units = this->_unitGen.generateUnits(protoInputs, protoOutputs, inputMode, op.getMqttPart(), true, op.getRelaxed());
}
catch (const std::exception &e) {
LOG(error) << this->_analyzerName << " " << an.getName() << ": Error when creating template job unit: " << e.what();
LOG(error) << this->_operatorName << " " << op.getName() << ": Error when creating template job unit: " << e.what();
delete units;
return false;
}
if(units->size() > 1) {
LOG(error) << this->_analyzerName << " " << an.getName() << ": Invalid job template unit, please check your configuration!";
LOG(error) << this->_operatorName << " " << op.getName() << ": Invalid job template unit, please check your configuration!";
delete units;
return false;
}
shared_ptr<UnitTemplate<SBase>> jobUnit = units->at(0);
delete units;
an.clearUnits();
op.clearUnits();
//if(!this->constructSensorTopics(*jobUnit, an))
//if(!this->constructSensorTopics(*jobUnit, op))
// return false;
if (this->unit(*jobUnit)) {
an.addToUnitCache(jobUnit);
op.addToUnitCache(jobUnit);
LOG(debug) << " Template job unit " + jobUnit->getName() + " generated.";
} else {
LOG(error) << " Template job unit " << jobUnit->getName() << " did not pass the final check!";
......@@ -130,4 +128,4 @@ protected:
boost::log::sources::severity_logger<boost::log::trivial::severity_level> lg;
};
#endif //PROJECT_JOBANALYZERCONFIGURATORTEMPLATE_H
#endif //PROJECT_JOBOPERATORCONFIGURATORTEMPLATE_H
//================================================================================
// Name : AnalyzerConfiguratorInterface.h
// Name : OperatorConfiguratorInterface.h
// Author : Alessio Netti
// Contact : info@dcdb.it
// Copyright : Leibniz Supercomputing Centre
// Description : Interface to configurators for data analyzer plugins.
// Description : Interface to configurators for operator plugins.
//================================================================================
//================================================================================
......@@ -25,44 +25,44 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//================================================================================
#ifndef PROJECT_ANALYZERCONFIGURATORINTERFACE_H
#define PROJECT_ANALYZERCONFIGURATORINTERFACE_H
#ifndef PROJECT_OPERATORCONFIGURATORINTERFACE_H
#define PROJECT_OPERATORCONFIGURATORINTERFACE_H
#include <string>
#include <vector>
#include "QueryEngine.h"
#include "AnalyzerInterface.h"
#include "OperatorInterface.h"
#include "globalconfiguration.h"
/**
* @brief Interface to configurators for data analyzer plugins
* @brief Interface to configurators for operator plugins
*
* @details This interface is the one exposed outside of the .dll library
* containing a plugin. Classes implementing this interface must
* perform configuration and instantiation of Analyzers objects, which
* perform configuration and instantiation of Operator objects, which
* are made accessible externally.
*
* @ingroup analyzer
* @ingroup operator
*/
class AnalyzerConfiguratorInterface {
class OperatorConfiguratorInterface {
public:
/**
* @brief Class constructor
*/
AnalyzerConfiguratorInterface() {}
OperatorConfiguratorInterface() {}
/**
* @brief Class destructor
*/
virtual ~AnalyzerConfiguratorInterface() {}
virtual ~OperatorConfiguratorInterface() {}
/**
* @brief Reads a config file and instantiates analyzers
* @brief Reads a config file and instantiates operators
*
* This method will read the config file to which the input path points, and instantiate analyzer
* This method will read the config file to which the input path points, and instantiate operator
* objects accordingly. This method must be implemented in derived classes.
*
* @param cfgPath Path of the input config file
......@@ -73,7 +73,7 @@ public:
/**
* @brief Repeats the configuration of the plugin
*
* This method will stop and clear all analyzers that were created, and repeats the configuration,
* This method will stop and clear all operators that were created, and repeats the configuration,
* by reading the file once again. This method must be implemented in derived classes.
*
* @return True if successful, false otherwise
......@@ -83,14 +83,14 @@ public:
/**
* @brief Clears the plugin configuration
*
* This method will stop and clear all analyzers that were created, returning the plugin to its
* This method will stop and clear all operators that were created, returning the plugin to its
* uninitialized state.
*
*/
virtual void clearConfig() = 0;
/**
* @brief Sets a structure containing global settings to be used during analyzer creation This
* @brief Sets a structure containing global settings to be used during operator creation This
* method must be implemented in derived classes.
*
*
......@@ -99,14 +99,14 @@ public:
virtual void setGlobalSettings(const pluginSettings_t& pluginSettings) = 0;
/**
* @brief Returns a vector of analyzers
* @brief Returns a vector of operators
*
* This method will return the internal vector of AnalyzerInterface objects, granting access
* This method will return the internal vector of OperatorInterface objects, granting access
* to their units and output sensors. This method must be implemented in derived classes.
*
* @return a vector of pointers to AnalyzerInterface objects
* @return a vector of pointers to OperatorInterface objects
*/
virtual std::vector<AnalyzerPtr>& getAnalyzers() = 0;
virtual std::vector<OperatorPtr>& getOperators() = 0;
/**
* @brief Prints the current plugin configuration
......@@ -122,9 +122,9 @@ protected:
};
// Typedefs for readable usage of create() and destroy() methods, required for dynamic libraries
typedef AnalyzerConfiguratorInterface* an_create_t();
typedef void an_destroy_t(AnalyzerConfiguratorInterface*);
typedef OperatorConfiguratorInterface* op_create_t();
typedef void op_destroy_t(OperatorConfiguratorInterface*);
#endif //PROJECT_ANALYZERCONFIGURATORINTERFACE_H
#endif //PROJECT_OPERATORCONFIGURATORINTERFACE_H
//================================================================================
// Name : AnalyzerInterface.h
// Name : OperatorInterface.h
// Author : Alessio Netti
// Contact : info@dcdb.it
// Copyright : Leibniz Supercomputing Centre
// Description : Interface to data analyzers.
// Description : Interface to data operators.
//================================================================================
//================================================================================
......@@ -26,13 +26,13 @@
//================================================================================
/**
* @defgroup analyzer Analyzer Plugins
* @defgroup operator Operator Plugins
* @ingroup analytics
*
* @brief Analyzer for the analytics plugin.
* @brief Operator for the analytics plugin.
*/
#ifndef PROJECT_ANALYZERINTERFACE_H
#define PROJECT_ANALYZERINTERFACE_H
#ifndef PROJECT_OPERATORINTERFACE_H
#define PROJECT_OPERATORINTERFACE_H
#include <atomic>
#include <memory>
......@@ -53,29 +53,29 @@ typedef struct {
} restResponse_t;
/**
* @brief Interface to data analyzers
* @brief Interface to data operators
*
* @details This interface supplies methods to instantiate, start and retrieve
* data from analyzers, which are "modules" that* implement data
* data from operators, which are "modules" that* implement data
* analytics models and are loaded by DCDB data analytics plugins. For
* it to be used in the DCDB data analytics framework, the analyzer
* it to be used in the DCDB data analytics framework, the operator
* must comply to this interface.
*
* An analyzer acts on "units", which are logical entities represented
* An operator acts on "units", which are logical entities represented
* by certain inputs and outputs. An unit can be, for example, a node,
* a CPU or a rack in a HPC system.
*
* @ingroup analyzer
* @ingroup operator
*/
class AnalyzerInterface {
class OperatorInterface {
public:
/**
* @brief Class constructor
*
* @param name Name of the analyzer
* @param name Name of the operator
*/
AnalyzerInterface(const string& name) :
OperatorInterface(const string& name) :
_name(name),
_mqttPart(""),
_isTemplate(false),
......@@ -100,7 +100,7 @@ public:
/**
* @brief Copy constructor
*/
AnalyzerInterface(const AnalyzerInterface& other) :
OperatorInterface(const OperatorInterface& other) :
_name(other._name),
_mqttPart(other._mqttPart),
_isTemplate(other._isTemplate),
......@@ -125,12 +125,12 @@ public:
/**
* @brief Class destructor
*/
virtual ~AnalyzerInterface() {}
virtual ~OperatorInterface() {}
/**
* @brief Assignment operator
*/
AnalyzerInterface& operator=(const AnalyzerInterface& other) {
OperatorInterface& operator=(const OperatorInterface& other) {
_name = other._name;
_mqttPart = other._mqttPart;
_isTemplate = other._isTemplate;
......@@ -156,7 +156,7 @@ public:
}
/**
* @brief Waits for the analyzer to complete its tasks
* @brief Waits for the operator to complete its tasks
*
* Does a busy wait until all dispatched handlers are finished (_pendingTasks == 0).
*/
......@@ -167,7 +167,7 @@ public:
}
/**
* @brief Initializes this analyzer
* @brief Initializes this operator
*
* This method initializes the timer used to schedule tasks. It can be overridden by derived
* classes.
......@@ -183,7 +183,7 @@ public:
* @brief Perform a REST-triggered PUT action
*
* This method must be implemented in derived classes. It will perform an action (if any)
* on the analyzer according to the input action string. Any thrown
* on the operator according to the input action string. Any thrown
* exceptions will be reported in the response string.
*
* @param action Name of the action to be performed
......@@ -194,26 +194,26 @@ public:
virtual restResponse_t REST(const string& action, const unordered_map<string, string>& queries) = 0;
/**
* @brief Starts this analyzer
* @brief Starts this operator
*
* This method must be implemented in derived classes. It will start the operation of the
* analyzer.
* operator.
*/
virtual void start() = 0;
/**
* @brief Stops this analyzer
* @brief Stops this operator
*
* This method must be implemented in derived classes. It will stop the operation of the
* analyzer.
* operator.
*/
virtual void stop() = 0;
/**
* @brief Adds an unit to this analyzer
* @brief Adds an unit to this operator
*
* This method must be implemented in derived classes. It must add the input UnitInterface to
* the internal structure storing units in the analyzer. Said unit must then be used during
* the internal structure storing units in the operator. Said unit must then be used during
* computation.
*
* @param u Shared pointer to a UnitInterface object
......@@ -221,7 +221,7 @@ public:
virtual void addUnit(UnitPtr u) = 0;
/**
* @brief Clears all the units contained in this analyzer
* @brief Clears all the units contained in this operator
*
* This method must be implemented in derived classes.
*/
......@@ -231,7 +231,7 @@ public:
* @brief Performs an on-demand compute task
*
* Unlike the protected computeAsync and compute methods, computeOnDemand allows to interactively
* perform data analytics queries on the analyzer, which must have the _streaming attribute set
* perform data analytics queries on the operator, which must have the _streaming attribute set
* to false. A unit is generated on the fly, corresponding to the input node given as input,
* and results are returned in the form of a map.
*
......@@ -241,7 +241,7 @@ public:
virtual map<string, reading_t> computeOnDemand(const string& node="") = 0;
/**
* @brief Prints the current analyzer configuration
* @brief Prints the current operator configuration
*
* @param ll Logging level at which the configuration is printed
*/
......@@ -287,40 +287,40 @@ protected:
* @brief Performs a compute task
*
* This method is tasked with scheduling the next compute task, and invoking the internal
* compute() method, which encapsulates the real logic of the analyzer. The compute method
* is automatically called over units as required by the Analyzer's configuration.
* compute() method, which encapsulates the real logic of the operator. The compute method
* is automatically called over units as required by the Operator's configuration.
*
*/
virtual void computeAsync() = 0;
// Name of this analyzer
// Name of this operator
string _name;
// MQTT part (see docs) of this analyzer
// MQTT part (see docs) of this operator
string _mqttPart;
// To distinguish between templates and actual analyzers
// To distinguish between templates and actual operators
bool _isTemplate;
// If the analyzer's units must be built in relaxed mode
// If the operator's units must be built in relaxed mode
bool _relaxed;
// If true, the analyzer is a duplicate of another
// If true, the operator is a duplicate of another
bool _duplicate;
// If true, the analyzer performs computation in streaming
// If true, the operator performs computation in streaming
bool _streaming;
// If true, the computation intervals are synchronized
bool _sync;
// Indicates whether the analyzer generates units dynamically at runtime, or only at initialization
// Indicates whether the operator generates units dynamically at runtime, or only at initialization
bool _dynamic;
// Indicates whether the analyzer generates hierarchical units that must be flattened (their sub-units exposed)
// Indicates whether the operator generates hierarchical units that must be flattened (their sub-units exposed)
bool _flatten;
// ID of the units this analyzer works on
// ID of the units this operator works on
int _unitID;
// Determines if the analyzer can keep running or must terminate
// Determines if the operator can keep running or must terminate
int _keepRunning;
// Minimum number of sensor values to be accumulated before output can be sent
unsigned int _minValues;
// Sampling period regulating compute batches
unsigned int _interval;
// Size of the cache in time for the output sensors in this analyzer
// Size of the cache in time for the output sensors in this operator
unsigned int _cacheInterval;
// Maximum number of units that can be contained in the unit cache
unsigned int _unitCacheLimit;
......@@ -340,6 +340,6 @@ protected:
};
//for better readability
using AnalyzerPtr = shared_ptr<AnalyzerInterface>;
using OperatorPtr = shared_ptr<OperatorInterface>;
#endif //PROJECT_ANALYZERINTERFACE_H
#endif //PROJECT_OPERATORINTERFACE_H
......@@ -3,7 +3,7 @@
// Author : Alessio Netti
// Contact : info@dcdb.it
// Copyright : Leibniz Supercomputing Centre
// Description : Helper template to generate Analyzer Units.