From b57ac7c86ffe8775924cccf41b50fe45c057774f Mon Sep 17 00:00:00 2001
From: imcovangent <I.vanGent@tudelft.nl>
Date: Tue, 23 Oct 2018 13:49:34 +0200
Subject: [PATCH] Improvement for Collaborative Optimization (CO) by scaling
 the consistency objective / constraint function J.

Former-commit-id: 7b80c9727f86cc705b56e5c2b19136c85c28a887
---
 kadmos/graph/graph_data.py   | 24 ++++++++++++++++++------
 kadmos/graph/graph_kadmos.py | 10 +++++++---
 2 files changed, 25 insertions(+), 9 deletions(-)

diff --git a/kadmos/graph/graph_data.py b/kadmos/graph/graph_data.py
index f6b59e216..ed3016693 100644
--- a/kadmos/graph/graph_data.py
+++ b/kadmos/graph/graph_data.py
@@ -3731,7 +3731,7 @@ class FundamentalProblemGraph(DataGraph, KeChainMixin):
 
         mdao_arch = self.graph['problem_formulation']['mdao_architecture']
         pre_functions = self.graph['problem_formulation']['function_ordering'][self.FUNCTION_ROLES[0]]
-        mg_function_ordering = dict(self.graph['problem_formulation']['function_ordering'])
+        mg_function_ordering = copy.deepcopy(self.graph['problem_formulation']['function_ordering'])
 
         # OPTIONS_ARCHITECTURE: IDF, MDF, unc-OPT, unc-DOE, con-DOE, CO, BLISS-2000
         if mdao_arch in self.OPTIONS_ARCHITECTURES[2:9]:
@@ -4821,7 +4821,9 @@ class FundamentalProblemGraph(DataGraph, KeChainMixin):
                                       local_des_vars_group+local_des_vars_copies_group,
                                       group_cof_obj_node,
                                       local_cnstrnt_vars_group,
-                                      label=sub_opts_labels[idx])
+                                      label=sub_opts_labels[idx],
+                                      package='SciPy', maximum_iterations=100,
+                                      convergence_tolerance=1e-6, constraint_tolerance=1e-6)
                 # Mark the final consistency objective value as a constraint and add it to the system level constraints
                 group_cof_obj_node_final = mdg.find_all_nodes(attr_cond=['related_to_schema_node', '==',
                                                                          group_cof_obj_node])
@@ -4836,7 +4838,8 @@ class FundamentalProblemGraph(DataGraph, KeChainMixin):
                                   objective_node,
                                   list(sys_lev_cnstrnts),
                                   label=sys_opt_label,
-                                  package='pyOptSparse')
+                                  package='pyOptSparse', maximum_iterations=200,
+                                  convergence_tolerance=1e-3, constraint_tolerance=1e-3)
 
             # Temp fix: make post-coupling functions into post-desvars
             for node in sa['functions_lists'][0]:
@@ -5660,7 +5663,7 @@ class MdaoDataGraph(DataGraph, MdaoMixin):
 
     def connect_consistency_objective_function(self, group_idx, ccv_mappings):
         """Method to add a consistency objective function. A consistency objective function between related values
-        y_1, y_1^c, y_2 and y_2^c would be: (y_1 - y_1^c)^2 + (y_2 - y_2^c)^2
+        y_1, y_1^c, y_2 and y_2^c would be: (((y_1 - y_1^c)/y_1_scaler)^2 + ((y_2 - y_2^c)/y_2_scaler)^2)**0.5
 
         :param group_idx: index of the subgroup
         :type group_idx: int
@@ -5686,12 +5689,21 @@ class MdaoDataGraph(DataGraph, MdaoMixin):
         for idx, (var1, var2) in enumerate(ccv_mappings.iteritems()):
             eq_lab1 = 'x{}_0'.format(idx)
             eq_lab2 = 'x{}_1'.format(idx)
+            eq_lab3 = 'x{}_sc'.format(idx)
             self.add_edge(var1, new_function_node, equation_label=eq_lab1)
             self.add_edge(var2, new_function_node, equation_label=eq_lab2)
+            # Add the scaler variable and connect accordingly
+            new_scaler_node = '/{}/scalers/{}'.format(var1.split('/')[1], '/'.join(var1.split('/')[2:]))
+            if not self.has_node(new_scaler_node):
+                self.add_node(new_scaler_node,
+                              category='variable',
+                              label='{}Scaler'.format(var1.split('/')[-1]),
+                              instance=1)
+            self.add_edge(new_scaler_node, new_function_node, equation_label=eq_lab3)
             if idx == 0:
-                math_expression = '({}-{})**2'.format(eq_lab2, eq_lab1)
+                math_expression = '(({}-{})/{})**2'.format(eq_lab2, eq_lab1, eq_lab3)
             else:
-                math_expression += '+({}-{})**2'.format(eq_lab2, eq_lab1)
+                math_expression += '+(({}-{})/{})**2'.format(eq_lab2, eq_lab1, eq_lab3)
         # Finally, add square root around expression
         math_expression = '(' + math_expression + ')**0.5'
         # Create the output objective node of the function and connect it
diff --git a/kadmos/graph/graph_kadmos.py b/kadmos/graph/graph_kadmos.py
index b85d1dc57..dbcbe5ef5 100644
--- a/kadmos/graph/graph_kadmos.py
+++ b/kadmos/graph/graph_kadmos.py
@@ -763,7 +763,7 @@ class KadmosGraph(nx.DiGraph, EquationMixin, VistomsMixin):
                 # Now add the pseudo-Coordinator to the graph and connect the input and output parameters
                 graph.add_node(pseudo_node, category='function', label='',
                                problem_role=graph.FUNCTION_ROLES[0],
-                               architecture_role=graph.ARCHITECTURE_ROLES_FUNS[0])
+                               architecture_role=graph.ARCHITECTURE_ROLES_FUNS[0], instance=1)
                 graph_inputs = graph.find_all_nodes(subcategory='all inputs')
                 graph_outputs = graph.find_all_nodes(subcategory='all outputs')
                 for inp in graph_inputs:
@@ -1264,7 +1264,8 @@ class KadmosGraph(nx.DiGraph, EquationMixin, VistomsMixin):
                     self.add_node(input['xpath'],
                                   category='variable',
                                   shape='o',
-                                  label=input['xpath'].split('/')[-1])  # TODO: Extend this to pick up XML attributes for description, note, unit, data_type
+                                  label=input['xpath'].split('/')[-1],
+                                  instance=1)  # TODO: Extend this to pick up XML attributes for description, note, unit, data_type
                 self.add_edge(input['xpath'], input_el[1].get('uID'))
 
         for output_el in outputs_list:
@@ -1275,7 +1276,8 @@ class KadmosGraph(nx.DiGraph, EquationMixin, VistomsMixin):
                     self.add_node(output['xpath'],
                                   category='variable',
                                   shape='o',
-                                  label=output['xpath'].split('/')[-1])  # TODO: Extend this to pick up XML attributes for description, note, unit, data_type
+                                  label=output['xpath'].split('/')[-1],
+                                  instance=1)  # TODO: Extend this to pick up XML attributes for description, note, unit, data_type
                 self.add_edge(output_el[1].get('uID'), output['xpath'])
 
         return
@@ -2083,6 +2085,8 @@ class KadmosGraph(nx.DiGraph, EquationMixin, VistomsMixin):
             self.nodes[n]['name'] = n
         if 'label' not in self.nodes[n]:
             self.nodes[n]['label'] = n
+        if 'instance' not in self.nodes[n]:
+            self.nodes[n]['instance'] = 1
 
     def add_edge(self, u, v, attr_dict=None, **attr):
         """Add an edge between u and v.
-- 
GitLab