From f44b8de2f36dc48d5a0df2599bff079be0328b4d Mon Sep 17 00:00:00 2001
From: Stefano Borini <sborini@enthought.com>
Date: Thu, 7 Jun 2018 11:04:22 +0100
Subject: [PATCH] Introduced KPI specification and removed is_kpi from classes.
 Tests next.

---
 force_bdss/core/data_value.py        |  6 ------
 force_bdss/core/kpi_specification.py | 10 ++++++++++
 force_bdss/core/output_slot_info.py  |  4 ----
 force_bdss/core_evaluation_driver.py | 11 +++++++++--
 force_bdss/core_mco_driver.py        | 13 +++----------
 force_bdss/mco/base_mco_model.py     |  4 ++++
 6 files changed, 26 insertions(+), 22 deletions(-)
 create mode 100644 force_bdss/core/kpi_specification.py

diff --git a/force_bdss/core/data_value.py b/force_bdss/core/data_value.py
index 9da19ab..51226d9 100644
--- a/force_bdss/core/data_value.py
+++ b/force_bdss/core/data_value.py
@@ -22,9 +22,6 @@ class DataValue(HasStrictTraits):
     #: A flag for the quality of the data.
     quality = Enum("AVERAGE", "POOR", "GOOD")
 
-    # Set by the engine. True if the data value contains a KPI.
-    is_kpi = Bool(False)
-
     def __str__(self):
 
         s = "{} {} = {}".format(
@@ -35,7 +32,4 @@ class DataValue(HasStrictTraits):
 
         s += " ({})".format(str(self.quality))
 
-        if self.is_kpi:
-            s += " (KPI)"
-
         return s
diff --git a/force_bdss/core/kpi_specification.py b/force_bdss/core/kpi_specification.py
new file mode 100644
index 0000000..672a9cf
--- /dev/null
+++ b/force_bdss/core/kpi_specification.py
@@ -0,0 +1,10 @@
+from traits.api import Enum, HasStrictTraits
+
+from force_bdss.local_traits import Identifier
+
+
+class KPISpecification(HasStrictTraits):
+    #: The user defined name of the variable containing the kpi value.
+    name = Identifier()
+
+    target = Enum("MINIMISE")
diff --git a/force_bdss/core/output_slot_info.py b/force_bdss/core/output_slot_info.py
index 8385fa4..6fd360d 100644
--- a/force_bdss/core/output_slot_info.py
+++ b/force_bdss/core/output_slot_info.py
@@ -13,7 +13,3 @@ class OutputSlotInfo(HasStrictTraits):
     """
     #: The user defined name of the variable containing the value.
     name = Identifier()
-
-    #: True if the value associated to this output slot must be exported as
-    #: a KPI.
-    is_kpi = Bool(False)
diff --git a/force_bdss/core_evaluation_driver.py b/force_bdss/core_evaluation_driver.py
index 151da8c..e89f724 100644
--- a/force_bdss/core_evaluation_driver.py
+++ b/force_bdss/core_evaluation_driver.py
@@ -65,7 +65,15 @@ def execute_workflow(workflow, data_values):
         available_data_values += ds_results
 
     log.info("Aggregating KPI data")
-    kpi_results = [dv for dv in available_data_values if dv.is_kpi]
+
+    kpi_results = []
+    kpi_names = [kpi.name for kpi in workflow.mco.kpis]
+
+    kpi_results = [
+        dv
+        for dv in available_data_values
+        if dv.name in kpi_names
+    ]
 
     return kpi_results
 
@@ -165,7 +173,6 @@ def _compute_layer_results(environment_data_values,
         # Add the names as specified by the user.
         for dv, output_slot_info in zip(res, model.output_slot_info):
             dv.name = output_slot_info.name
-            dv.is_kpi = output_slot_info.is_kpi
 
         # If the name was not specified, simply discard the value,
         # because apparently the user is not interested in it.
diff --git a/force_bdss/core_mco_driver.py b/force_bdss/core_mco_driver.py
index 733b34b..46b9cda 100644
--- a/force_bdss/core_mco_driver.py
+++ b/force_bdss/core_mco_driver.py
@@ -88,17 +88,10 @@ class CoreMCODriver(BaseCoreDriver):
 
     @on_trait_change("mco:started")
     def _deliver_start_event(self):
-        output_kpis = []
-        for layer in self.workflow.execution_layers:
-            for data_source in layer.data_sources:
-                output_kpis.extend(
-                    info for info in data_source.output_slot_info
-                    if info.is_kpi
-                )
-
+        mco_model = self.workflow.mco
         self._deliver_event(MCOStartEvent(
-            input_names=tuple(p.name for p in self.workflow.mco.parameters),
-            output_names=tuple([on.name for on in output_kpis])
+            input_names=tuple(p.name for p in mco_model.parameters),
+            output_names=tuple([kpi.name for kpi in mco_model.kpis])
         ))
 
     @on_trait_change("mco:finished")
diff --git a/force_bdss/mco/base_mco_model.py b/force_bdss/mco/base_mco_model.py
index f1e545a..af89084 100644
--- a/force_bdss/mco/base_mco_model.py
+++ b/force_bdss/mco/base_mco_model.py
@@ -1,5 +1,6 @@
 from traits.api import ABCHasStrictTraits, Instance, List
 
+from force_bdss.core.kpi_specification import KPISpecification
 from .parameters.base_mco_parameter import BaseMCOParameter
 from .i_mco_factory import IMCOFactory
 
@@ -20,6 +21,9 @@ class BaseMCOModel(ABCHasStrictTraits):
     # A list of the parameters for the MCO
     parameters = List(BaseMCOParameter, visible=False)
 
+    # A list of KPI specification objects and their objective.
+    kpis = List(KPISpecification, visible=False)
+
     def __init__(self, factory, *args, **kwargs):
         self.factory = factory
         super(BaseMCOModel, self).__init__(*args, **kwargs)
-- 
GitLab