diff --git a/kadmos/graph/graph_data.py b/kadmos/graph/graph_data.py
index 82c7eafdf6201e5d8918d32b86183d6d31fad539..25fc5f6e73af3eefd6a1be04c0be61367571ff78 100644
--- a/kadmos/graph/graph_data.py
+++ b/kadmos/graph/graph_data.py
@@ -20,7 +20,6 @@ from graph_kadmos import KadmosGraph
 
 from mixin_mdao import MdaoMixin
 from mixin_kechain import KeChainMixin
-from mixin_rce import RceMixin
 
 
 # Settings for the logger
@@ -1838,7 +1837,7 @@ class FundamentalProblemGraph(DataGraph, KeChainMixin):
         return mdg
 
 
-class MdaoDataGraph(DataGraph, MdaoMixin, RceMixin):
+class MdaoDataGraph(DataGraph, MdaoMixin):
 
     def __init__(self, *args, **kwargs):
         super(MdaoDataGraph, self).__init__(*args, **kwargs)
diff --git a/kadmos/graph/mixin_rce.py b/kadmos/graph/mixin_rce.py
deleted file mode 100644
index 77e82a959fe6d68c2d704a3e7d7a12bb99bf94b5..0000000000000000000000000000000000000000
--- a/kadmos/graph/mixin_rce.py
+++ /dev/null
@@ -1,1178 +0,0 @@
-# Imports
-import json
-import os
-import logging
-
-import networkx as nx
-
-from operator import itemgetter
-
-from ..utilities.general import get_list_entries
-
-
-# Settings for the logger
-logger = logging.getLogger(__name__)
-
-
-class RceMixin(object):
-
-    def get_rce_graph(self, MPG, rce_working_dir, rce_wf_filename, name='RCE graph', add_output_filters=True,
-                      uid_length=8):
-        """This function determines the RCE graph for a workflow.
-
-        Such an RCE graph can be directly translated into an RCE
-        workflow file. The method in this function is to use the MDG as a basis. This MDG is then analyzed and extended to
-        meet the RCE workflow scripting requirements. The FPG is used to assess the process of the workflow, mainly to find
-        any nested loops.
-
-        :type self: MdaoDataGraph
-        :param MPG: the MDAO process graph of the MDO problem
-        :type MPG: MdaoProcessGraph
-        :param rce_working_dir: subdirectory in which the RCE workflow file should be saved
-        :type rce_working_dir: str
-        :param rce_wf_filename: name of the workflow file
-        :type rce_wf_filename: str
-        :param name: name of the graph (used in plots and visualizations)
-        :type name: str
-        :param name: setting to add output filters on the function blocks
-        :type name: str
-        :param uid_length: setting for the length of the unique identifiers for variables
-        :type uid_length: int
-        :return: graph that is directly translatable into an RCE workflow
-        :rtype: RceGraph
-        """
-
-        # Output in log
-        logger.info('Creating RCE graph...')
-
-        # Assert input
-        from graph_process import MdaoProcessGraph
-        assert type(MPG) is MdaoProcessGraph, "MPG input needs to be of type MdaoProcessGraph"
-        assert type(rce_working_dir) is str
-        assert type(rce_wf_filename) is str
-        assert type(name) is str
-        assert isinstance(uid_length, int)
-        assert uid_length >= 0, 'uid_length should be 0 or larger.'
-
-        # Make clean copies of the input graphs
-        self = self.cleancopy()
-        MPG = MPG.cleancopy()
-
-        # Check MDG and MPG
-        self.check(raise_error=True)
-        MPG.check(raise_error=True)
-
-        # Create graph object
-        from graph_process import RceGraph
-        rce_graph = RceGraph(self, rce_working_dir=rce_working_dir, rce_wf_filename=rce_wf_filename, name=name)
-
-        # Add diagonal positions to rce_graph based on MPG
-        rce_graph.add_diagonal_positions(MPG)
-
-        # Add database of friendly node uids for each UXPath present in the MDG
-        rce_graph.add_uxpath_uids(self, uid_length=uid_length)
-
-        # ------------------------------------------------------------------------------------------------------------ #
-        #                                        STEP 1: Assess iterative nodes                                        #
-        # ------------------------------------------------------------------------------------------------------------ #
-        # In this step the iterative nodes in the graph are determined and (in case of nesting) grouped.
-        (iterative_nodes, process_info, nested_functions) = MPG.get_nested_process_ordering()
-
-        # ------------------------------------------------------------------------------------------------------------ #
-        #                                        STEP 2: Output of the Coordinator                                     #
-        # ------------------------------------------------------------------------------------------------------------ #
-        # Handle the output of the Coordinator block: add COOR-out node, connect it to the right functions, and collect
-        # required XPaths.
-
-        # Start node group dictionary
-        # Node groups are used in the RCE workflow to make labels
-        coor_lab = self.COORDINATOR_LABEL
-        node_grouping = {coor_lab: []}
-
-        # Add COOR-out block
-        coor_out_id = coor_lab + '-out'
-        assert not rce_graph.has_node(coor_out_id), 'Node %s already defined in the graph.' % coor_out_id
-        rce_graph.add_node(coor_out_id,
-                           category='function',
-                           shape='8',
-                           rce_role=self.RCE_ROLES_FUNS[0],  # Input Provider
-                           label=coor_out_id,
-                           level=None,
-                           diagonal_position=0,
-                           xpaths=[],
-                           input_filenames=[coor_out_id + '_' + rce_wf_filename.replace('.wf', '') + '.xml'])
-        node_grouping[coor_lab].append(coor_out_id)
-
-        # Add COOR-start node for each iterative node that needs one (converger, optimizer)
-        for idx, iterative_node in enumerate(iterative_nodes):
-            # Add COOR-start block if iterative node is a converger or optimizer
-            if self.node[iterative_node]['architecture_role'] in get_list_entries(self.ARCHITECTURE_ROLES_FUNS,1,2):
-                rce_graph.insert_node_on_diagonal(coor_lab+ '-start-' + str(iterative_node), idx + 1,
-                                                  {'category': 'function',
-                                                   'rce_role': self.RCE_ROLES_FUNS[0],  # Input Provider
-                                                   'shape': '8',
-                                                   'label': coor_lab+ '-start-' + str(iterative_node),
-                                                   'level': None,
-                                                   'diagonal_position': idx + 1,
-                                                   'xpaths': [],
-                                                   'input_filenames': [coor_lab+ '-start_' + iterative_node + '_' +
-                                                                       rce_wf_filename.replace('.wf', '') + '.xml']})
-                node_grouping[coor_lab].append(coor_lab + '-start-' + str(iterative_node))
-
-        # Loop over each outgoing edge from the Coordinator node
-        out_edges_coordinator = rce_graph.out_edges(self.COORDINATOR_STRING)
-        for (u, v) in out_edges_coordinator:
-            # Determine targets of variable node v
-            v_out_edges = rce_graph.out_edges(v)
-            # Add XPath of the node to the xpath attribute of the correct INI node
-            if 'architecture_role' in rce_graph.node[v]:
-                new_xpath = rce_graph.node[v]['related_to_schema_node']
-                # Check for initial guess coupling/design variable
-                if rce_graph.node[v]['architecture_role'] in get_list_entries(self.ARCHITECTURE_ROLES_VARS, 0, 3) and \
-                                v_out_edges[0][1] in iterative_nodes:
-                    assert len(v_out_edges) == 1
-                    correct_coor_node = coor_lab + '-start-' + str(v_out_edges[0][1])
-                    rce_graph.node[correct_coor_node]['xpaths'].append(new_xpath)
-                else:
-                    correct_coor_node = coor_out_id
-                    rce_graph.node[correct_coor_node]['xpaths'].append(new_xpath)
-            else:
-                if 'related_to_schema_node' in rce_graph.node[v]:
-                    new_xpath = rce_graph.node[v]['related_to_schema_node']
-                else:
-                    new_xpath = v
-                correct_coor_node = coor_out_id
-                rce_graph.node[correct_coor_node]['xpaths'].append(new_xpath)
-
-            # Remove edge between Coordinator and variable
-            rce_graph.remove_edge(u, v)
-
-            # Loop over outgoing edges of the node, connect COOR to right function, remove edge between variable and
-            # function
-            for (vc, w) in v_out_edges:
-                if rce_graph.has_edge(correct_coor_node, w):
-                    rce_graph[correct_coor_node][w]['xpaths'].append(new_xpath)
-                else:
-                    rce_graph.add_edge(correct_coor_node, w, xpaths=[new_xpath])
-                rce_graph.remove_edge(vc, w)
-
-            # Remove variable node if it has become a hole (no incoming and outgoing edges)
-            if rce_graph.in_degree(v) == 0 and rce_graph.out_degree(v) == 0:
-                rce_graph.remove_node(v)
-
-        # ------------------------------------------------------------------------------------------------------------ #
-        #                                           STEP 3: Iterators                                                  #
-        # ------------------------------------------------------------------------------------------------------------ #
-        # Add the iterators to the graph.
-
-        # Collect the pre-coupling, pre-iter, and post-iter functions
-        precoup_funcs = self.find_all_nodes(attr_cond=['architecture_role', '==', self.ARCHITECTURE_ROLES_FUNS[4]])
-        precoup_unsorted = [(fun, rce_graph.node[fun]['diagonal_position']) for fun in precoup_funcs]
-        precoup_sorted = [item[0] for item in sorted(precoup_unsorted, key=itemgetter(1))]
-
-        preiter_funcs = self.find_all_nodes(attr_cond=['architecture_role', '==', self.ARCHITECTURE_ROLES_FUNS[5]])
-        preiter_unsorted = [(fun, rce_graph.node[fun]['diagonal_position']) for fun in preiter_funcs]
-        preiter_sorted = [item[0] for item in sorted(preiter_unsorted, key=itemgetter(1))]
-
-        postiter_funcs = self.find_all_nodes(attr_cond=['architecture_role', '==', self.ARCHITECTURE_ROLES_FUNS[6]])
-        postiter_unsorted = [(fun, rce_graph.node[fun]['diagonal_position']) for fun in postiter_funcs]
-        postiter_sorted = [item[0] for item in sorted(postiter_unsorted, key=itemgetter(1))]
-
-        # Collect coupled functions in order of diagonal position (coupled analysis)
-        coup_funcs = self.find_all_nodes(attr_cond=['architecture_role', '==', self.ARCHITECTURE_ROLES_FUNS[7]])
-        coups_unsorted = [(fun, rce_graph.node[fun]['diagonal_position']) for fun in coup_funcs]
-        coups_sorted = [item[0] for item in sorted(coups_unsorted, key=itemgetter(1))]
-
-        # Collect independent output functions and optimizer functions in order of diagonal position
-        post_funcs = self.find_all_nodes(attr_cond=['architecture_role', '==', self.ARCHITECTURE_ROLES_FUNS[8]])
-        iofs = []
-        opfs = []
-        for post_func in post_funcs:
-            # Determine the targets of the function
-            fun_targs = self.get_targets(post_func)
-            for fun_targ in fun_targs:
-                if 'architecture_role' in self.node[fun_targ]:
-                    if self.node[fun_targ]['architecture_role'] == self.ARCHITECTURE_ROLES_VARS[5]: # final output
-                        opfs.append(post_func)
-                        break
-                elif self.DOE_STRING in iterative_nodes: # for DOE only opfs exist
-                    opfs.append(post_func)
-                    break
-                if fun_targ == fun_targs[-1]:
-                    iofs.append(post_func)
-        # Sort iofs
-        iofs_unsorted = [(iof, rce_graph.node[iof]['diagonal_position']) for iof in iofs]
-        iofs_sorted = [item[0] for item in sorted(iofs_unsorted, key=itemgetter(1))]
-        # Append consistency constraint function(s) to opfs
-        opfs.extend(self.find_all_nodes(attr_cond=['architecture_role', '==', self.ARCHITECTURE_ROLES_FUNS[9]]))
-        # Sort opfs
-        opfs_unsorted = [(opf, rce_graph.node[opf]['diagonal_position']) for opf in opfs]
-        opfs_sorted = [item[0] for item in sorted(opfs_unsorted, key=itemgetter(1))]
-
-        # print 'CHECK&$%'
-        # print 'precoup:'
-        # print precoup_sorted
-        # print 'preiter:'
-        # print preiter_sorted
-        # print 'postiter:'
-        # print postiter_sorted
-        # print 'coups:'
-        # print coups_sorted
-        # print 'iofs:'
-        # print iofs_sorted
-        # print 'opfs:'
-        # print opfs_sorted
-        # print 'iterative analysis:'
-        # print iterative_nodes
-        # print process_info
-        # print nested_functions
-
-        # Appendices for iter node names:
-        first_iter_name_app = '-start_values'
-        second_iter_name_app = ''
-        third_iter_name_app = '-XML-load-conv'
-        fourth_iter_name_app = '-XML-merge-conv'
-        fifth_iter_name_app = '-XML-load-final'
-
-        # Define empty iter_node_name (in case no iterative_nodes are present)
-        iter_node_name = ''
-
-        # Add all iterators
-        for idx, iter_node_name in enumerate(iterative_nodes):
-            node_grouping[iter_node_name] = []
-            iter_node = rce_graph.node[iter_node_name]
-            if iter_node['architecture_role'] in get_list_entries(self.ARCHITECTURE_ROLES_FUNS,1,2,3): # opt, conv, doe
-                if iter_node['architecture_role'] == self.ARCHITECTURE_ROLES_FUNS[2]:  # converger
-                    rce_role = self.RCE_ROLES_FUNS[5]  # Converger
-                    additional_attributes = dict()
-                elif iter_node['architecture_role'] == self.ARCHITECTURE_ROLES_FUNS[1]:  # optimizer
-                    rce_role = self.RCE_ROLES_FUNS[6]  # Optimizer
-                    additional_attributes = {'design_variables': self.node[iter_node_name]['design_variables'],
-                                             'objective_variable': self.node[iter_node_name]['objective_variable'],
-                                             'constraint_variables': self.node[iter_node_name]['constraint_variables']}
-                elif iter_node['architecture_role'] == self.ARCHITECTURE_ROLES_FUNS[3]:  # DOE
-                    rce_role = self.RCE_ROLES_FUNS[9]  # DOE
-                    additional_attributes = {'design_variables': self.node[iter_node_name]['design_variables'],
-                                             'quantities_of_interest':
-                                                 self.node[iter_node_name]['quantities_of_interest'],
-                                             'settings': self.node[iter_node_name]['settings']}
-
-                # Adjust iterator block to XML Merger (XML to floats for RCE component)
-                if rce_graph.has_node(coor_lab + '-start-' + iter_node_name):
-                    xpaths = rce_graph.node[coor_lab + '-start-' + iter_node_name]['xpaths']
-                    filenames = [coor_lab + '-start_' + iter_node_name + '_' +
-                                                                       rce_wf_filename.replace('.wf', '') + '.xml']
-                else:
-                    xpaths = self.node[iter_node_name]['design_variables'].keys()
-                    filenames = []
-                iter_node['category'] = 'function'
-                iter_node['rce_role'] = self.RCE_ROLES_FUNS[1]  # XML Merger
-                iter_node['xpaths'] = xpaths
-                iter_node['forwarded_inputs'] = []
-                first_iter_node = iter_node_name + first_iter_name_app
-                rce_graph = nx.relabel_nodes(rce_graph, {iter_node_name: first_iter_node})  # TODO FIX THIS!
-                rce_graph.graph['kb_path'] = self.graph['kb_path']                          # TODO FIX THIS!
-                rce_graph = RceGraph(rce_graph, rce_working_dir=rce_working_dir, # TODO FIX THIS!
-                                                   rce_wf_filename=rce_wf_filename, name=name) # TODO FIX THIS!
-                first_node = rce_graph.node[first_iter_node]
-                first_node['label'] = first_iter_node
-
-                # Add iterative block
-                second_iter_node = iter_node_name + second_iter_name_app
-                rce_graph.insert_node_on_diagonal(second_iter_node, first_node['diagonal_position'] + 1,
-                                                  {'category': 'function',
-                                                   'rce_role': rce_role,
-                                                   'shape': '8',
-                                                   'label': second_iter_node,
-                                                   'level': None,
-                                                   'xpaths': first_node['xpaths'],
-                                                   'forwarded_inputs': [],
-                                                   'input_filenames': filenames,
-                                                   'is_nested_loop': False})
-
-                # Add additional attributes (design, objective, constraint variables, settings, etc.)
-                for key, item in additional_attributes.iteritems():
-                    rce_graph.node[second_iter_node][key] = item
-
-                # Add XML load block (floats to XML for DAs)
-                third_iter_node = iter_node_name + third_iter_name_app
-                rce_graph.insert_node_on_diagonal(third_iter_node, first_node['diagonal_position'] + 2,
-                                                  {'category': 'function',
-                                                   'rce_role': self.RCE_ROLES_FUNS[2],  # XML Loader
-                                                   'shape': '8',
-                                                   'label': third_iter_node,
-                                                   'level': None,
-                                                   'xpaths': first_node['xpaths'],
-                                                   'forwarded_inputs': []})
-
-                # Add XML Merger (iter_node XMLs to floats during converging)
-                fourth_iter_node = iter_node_name + fourth_iter_name_app
-                if rce_role == self.RCE_ROLES_FUNS[5]:  # Converger
-                    fourth_iter_node_xpaths = first_node['xpaths']
-                elif rce_role == self.RCE_ROLES_FUNS[6]:  # Optimizer
-                    fourth_iter_node_xpaths = first_node['objective_variable'] + \
-                                              first_node['constraint_variables'].keys()
-                elif rce_role == self.RCE_ROLES_FUNS[9]:  # DOE
-                    fourth_iter_node_xpaths = first_node['quantities_of_interest']
-                rce_graph.insert_node_on_diagonal(fourth_iter_node, first_node['diagonal_position'] + 3,
-                                                  {'category': 'function',
-                                                   'rce_role': self.RCE_ROLES_FUNS[1],  # XML Merger
-                                                   'shape': '8',
-                                                   'label': fourth_iter_node,
-                                                   'level': None,
-                                                   'xpaths': fourth_iter_node_xpaths,
-                                                   'forwarded_inputs': []})
-
-                # Add XML load block (floats to XML for results)
-                fifth_iter_node = iter_node_name + fifth_iter_name_app
-                rce_graph.insert_node_on_diagonal(fifth_iter_node,
-                                                  first_node['diagonal_position'] + 4,
-                                                  {'category': 'function',
-                                                   'rce_role': self.RCE_ROLES_FUNS[2],  # XML Loader
-                                                   'shape': '8',
-                                                   'label': fifth_iter_node,
-                                                   'level': None,
-                                                   'xpaths': first_node['xpaths'],
-                                                   'forwarded_inputs': []})
-
-                # Add edges
-                rce_graph.add_edge(first_iter_node, second_iter_node, xpaths=first_node['xpaths'], forwarded_inputs=[])
-                rce_graph.add_edge(second_iter_node, fifth_iter_node, xpaths=first_node['xpaths'], forwarded_inputs=[])
-                rce_graph.add_edge(second_iter_node, third_iter_node, xpaths=first_node['xpaths'], forwarded_inputs=[])
-                rce_graph.add_edge(fourth_iter_node, second_iter_node, xpaths=fourth_iter_node_xpaths,
-                                   forwarded_inputs=[])
-
-                # Reconnect outgoing edges of first node
-                first_node_out_edges = rce_graph.out_edges(first_iter_node)
-                rce_graph.get_nodes_subcategory()
-                for edge in first_node_out_edges:
-                    var_node = edge[1]
-                    var_node_cat = rce_graph.node[var_node]['category']
-                    var_node_subcat = rce_graph.node[var_node]['subcategory']
-                    if 'architecture_role' in self.node[var_node]:
-                        var_arch_role = self.node[var_node]['architecture_role']
-                    else:
-                        var_arch_role = None
-                    if iter_node_name == self.CONVERGER_STRING:  # Converger
-                        assert var_node == second_iter_node or 'architecture_role' in self.node[var_node], \
-                            'The ' + str(iter_node_name) + \
-                            ' node has an output (' + str(var_node) + ') which is not an "architecture element".'
-                        assert var_node == second_iter_node or var_arch_role == self.ARCHITECTURE_ROLES_VARS[2] \
-                               or iter_node_name == 'Optimizer', \
-                            'The MDA node has an output which is not an "coupling copy variable".'
-                    if iter_node_name == self.OPTIMIZER_STRING:  # Optimizer
-                        assert var_node == second_iter_node or var_node_cat == 'variable', \
-                            'The Optimizer node has an output (' \
-                            + str(var_node) + ') which is not a "variable".'
-                        assert var_node == second_iter_node or var_arch_role in \
-                                                               get_list_entries(self.ARCHITECTURE_ROLES_VARS,2,4) or \
-                               var_node_subcat in self.NODE_GROUP_SUBCATS['all couplings'], \
-                            'The Optimizer node has an output which is not a "coupling copy variable" ' \
-                            'or "final design variable".'
-                    # Reset edge source to third node (XML load), and make the linked MDA analyses the source
-                    # Check if the target of the variable node leads to an mda.
-                    var_in_edges = rce_graph.out_edges(var_node)
-                    for var_in_edge in var_in_edges:
-                        target = var_in_edge[1]
-                        if target in postiter_sorted + coups_sorted + opfs_sorted + iofs_sorted:
-                            # Determine XPath of the variable node
-                            if 'related_to_schema_node' in rce_graph.node[var_node]:
-                                new_xpath = rce_graph.node[var_node]['related_to_schema_node']
-                            else:
-                                new_xpath = var_node
-                            # Add direct edge between third or fifth node and the XPath in the pipeline
-                            if target in postiter_sorted + coups_sorted + opfs_sorted:
-                                conv_source = third_iter_node
-                            elif target in iofs_sorted:
-                                conv_source = fifth_iter_node
-                            # Now add edge or enrich xpath data
-                            if rce_graph.has_edge(conv_source, target):
-                                rce_graph[conv_source][target]['xpaths'].append(new_xpath)
-                            else:
-                                rce_graph.add_edge(conv_source, target, xpaths=[new_xpath], forwarded_inputs=[])
-                            # Remove edges between 'variable node-->target'
-                            rce_graph.remove_edge(var_node, target)
-                            # Remove variable node if it has no more outgoing edges
-                            if rce_graph.out_degree(var_node) == 0:
-                                rce_graph.remove_node(var_node)
-                        if target == self.COORDINATOR_STRING:
-                            # Determine XPath of the variable node
-                            if 'related_to_schema_node' in rce_graph.node[var_node]:
-                                new_xpath = rce_graph.node[var_node]['related_to_schema_node']
-                            else:
-                                new_xpath = var_node
-                            # Simply change the edge from first node to second node
-                            rce_graph.add_edge(second_iter_node, var_in_edge[0], xpaths=[new_xpath],
-                                               forwarded_inputs=[])
-                            rce_graph.remove_edge(first_iter_node, var_in_edge[0])
-
-                # Reconnect incoming edges with coupling variables coming from coupled functions
-                first_node_in_edges = rce_graph.in_edges(first_iter_node)
-                for edge in first_node_in_edges:
-                    var_node = edge[0]
-                    var_node_cat = rce_graph.node[var_node]['category']
-                    var_node_subcat = rce_graph.node[var_node]['subcategory']
-                    if iter_node_name == self.CONVERGER_STRING:  # Converger
-                        assert var_node == coor_lab + '-start-' + iter_node_name or var_node_cat == 'variable', \
-                            'The coupled function node has an input (' + str(var_node) + ') which is not an variable.'
-                        assert var_node == coor_lab + '-start-' + iter_node_name or \
-                               var_node_subcat in self.NODE_GROUP_SUBCATS['all couplings'], \
-                            'The coupled function node has an input (' + str(var_node) + ') which is not a coupling.'
-                    elif iter_node_name == self.OPTIMIZER_STRING:  # Optimizer
-                        assert var_node == coor_lab + '-start-' + iter_node_name or var_node_cat == 'variable', \
-                            'The Optimizer node has an input (' + str(var_node) + ') which is not a variable.'
-                        assert var_node == coor_lab + '-start-' + iter_node_name or var_node_cat == 'variable', \
-                            'The Optimizer node has an input (' + str(var_node) + ') which is not a variable.'
-                    # Reset edge target to fourth node (XML Merger), and make the linked MDA analyses the source
-                    # Check if the source of the variable node leads to an mda
-                    var_in_edges = rce_graph.in_edges(var_node)
-                    for var_in_edge in var_in_edges:
-                        source = var_in_edge[0]
-                        if source in postiter_sorted + coups_sorted + opfs_sorted:
-                            # Determine XPath of the variable node
-                            new_xpath = var_node
-                            # Add direct edge between the analysis and the fourth node
-                            if rce_graph.has_edge(source, fourth_iter_node):
-                                rce_graph[source][fourth_iter_node]['xpaths'].append(new_xpath)
-                            else:
-                                rce_graph.add_edge(source, fourth_iter_node, xpaths=[new_xpath], forwarded_inputs=[])
-                            # Remove edge between 'variable node-->iterative node'
-                            rce_graph.remove_edge(var_node, first_iter_node)
-                            # Remove edges between 'analysis-->variable node' if the variable node has no other targets
-                            if rce_graph.out_degree(var_node) == 0:
-                                rce_graph.remove_edge(source, var_node)
-                            # Remove variable node if it has no more incoming edges
-                            if rce_graph.in_degree(var_node) == 0:
-                                rce_graph.remove_node(var_node)
-
-                if rce_graph.node[second_iter_node]['rce_role'] == self.RCE_ROLES_FUNS[9]:  # DOE
-                    # Remove first and fifth node for DOE
-                    rce_graph.remove_node_from_diagonal(first_iter_node)
-                    rce_graph.remove_node_from_diagonal(fifth_iter_node)
-                    # Create node group
-                    node_grouping[iter_node_name].extend([second_iter_node, third_iter_node, fourth_iter_node])
-                else:
-                    # Create node group
-                    node_grouping[iter_node_name].extend([first_iter_node, second_iter_node, third_iter_node,
-                                                          fourth_iter_node, fifth_iter_node])
-
-        # Add nested loop edge between iterative nodes and add is_nested_loop boolean on nested iterator
-        if process_info['iter_nesting']:
-            for top_iter, nested_iters in process_info['iter_nesting'].iteritems():
-                for nested_iter in nested_iters:
-                    # Add outer loop done boolean as edge
-                    if not rce_graph.has_edge(top_iter+second_iter_name_app, nested_iter+second_iter_name_app):
-                        rce_graph.add_edge(top_iter, nested_iter, xpaths=[], forwarded_inputs=[],
-                                           rce_specific=['Outer loop done'])
-                    else:
-                        rce_graph[top_iter+second_iter_name_app][nested_iter+second_iter_name_app]['rce_specific'] = \
-                            ['Outer loop done']
-                    # Set nested loop Boolean to True for nested iterative item
-                    rce_graph.node[nested_iter+second_iter_name_app]['is_nested_loop'] = True
-                    # Adjust COOR-start-connection to top-level iterator and make it a forwarded input to the nested item
-                    xpaths = rce_graph[coor_lab + '-start-'+nested_iter][nested_iter+first_iter_name_app]['xpaths']
-                    rce_graph.remove_edge(coor_lab + '-start-'+nested_iter, nested_iter+first_iter_name_app)
-                    rce_graph.add_edge(coor_lab + '-start-'+nested_iter, top_iter+second_iter_name_app, xpaths=[],
-                                       forwarded_inputs=[nested_iter+'convvaluesXML'])
-                    rce_graph.add_edge(top_iter + second_iter_name_app, nested_iter + first_iter_name_app, xpaths=[],
-                                       forwarded_inputs=[nested_iter+'convvaluesXML'])
-                    rce_graph.node[top_iter+second_iter_name_app]['forwarded_inputs'].append(nested_iter+'convvaluesXML')
-                    rce_graph.add_edge(nested_iter+fifth_iter_name_app, top_iter + second_iter_name_app, xpaths=[],
-                                       forwarded_inputs=[nested_iter+'convvaluesXML'])
-
-        # ------------------------------------------------------------------------------------------------------------ #
-        #                                       STEP 4: Function data connections                                      #
-        # ------------------------------------------------------------------------------------------------------------ #
-        # Create the right connections between functions.
-
-        # Analyze inter-analyses nodes
-        all_sorted = precoup_sorted + preiter_sorted + postiter_sorted + coups_sorted + opfs_sorted + iofs_sorted
-        iter_forwarded_inputs = dict()
-        for key in process_info['function_grouping']:
-            iter_forwarded_inputs[key] = []
-
-        # Loop over all analyses to make the right connections
-        for idx, analysis in enumerate(all_sorted):
-            # Determine the iterator associated with the analysis
-            iter_node_name = None
-            iter_is_nested = False
-
-            # Determine the iterator belonging to the analysis
-            if iterative_nodes and analysis not in preiter_sorted+precoup_sorted:
-                iter_node_name = next((iter for iter, analyses in
-                                      process_info['function_grouping'].items() if analysis in analyses), None)
-                assert iter_node_name, 'The right iterator could not be found.'
-
-                # Determine if the iterator found is nested
-                iter_is_nested = False if (iter_node_name in process_info['iter_nesting'] or
-                                           not process_info['iter_nesting']) else True
-
-                if iter_is_nested:
-                    top_level_iter = next((top_level_iter for top_level_iter, nested_iters in
-                                           process_info['iter_nesting'].items() if iter_node_name in nested_iters),
-                                          None)
-                    assert top_level_iter, 'The right top level iterator could not be found.'
-
-            # Add new node grouping for each function
-            node_grouping[analysis] = [analysis]
-            # Check outgoing edges
-            analysis_out_edges = rce_graph.out_edges(analysis)
-            for (src, out_node) in analysis_out_edges:
-                # Check if outgoing edge is linked to a variable node
-                if rce_graph.node[out_node]['category'] == 'variable':
-                    var_in_edges = rce_graph.out_edges(out_node)
-                else:
-                    var_in_edges = []
-                for (var_node, target) in var_in_edges:
-                    # Check if the target of the variable node leads to a coupled or optimizer function
-                    if set([target]).intersection((postiter_sorted + coups_sorted + opfs_sorted)):
-                        # Determine XPath of the variable node
-                        if 'related_to_schema_node' in rce_graph.node[var_node]:
-                            new_xpath = rce_graph.node[var_node]['related_to_schema_node']
-                        else:
-                            new_xpath = var_node
-                        # Assess if a direct edge is allowed between the analyses
-                        if iter_is_nested and analysis in process_info['function_grouping'][iter_node_name] and \
-                            target in process_info['function_grouping'][iter_node_name]:
-                            direct_edge_allowed = True
-                        elif not iter_is_nested or src in preiter_sorted+precoup_sorted:
-                            direct_edge_allowed = True
-                        else:
-                            direct_edge_allowed = False
-                        # Add direct edge between two coupled functions and the XPath in the pipeline (if iterator is
-                        # not nested or if both analysis are part of the same iterator)
-                        if rce_graph.has_edge(analysis, target) and direct_edge_allowed:
-                            rce_graph[analysis][target]['xpaths'].append(new_xpath)
-                        elif not rce_graph.has_edge(analysis, target) and direct_edge_allowed:
-                            rce_graph.add_edge(analysis, target, xpaths=[new_xpath])
-
-                        # If the xpath is not a coupling variable to be converged by the converger, then add the output
-                        # of the disciplinary analysis as forwarded input.
-                        if src not in preiter_sorted + precoup_sorted:
-                            if iterative_nodes and rce_graph.node[iter_node_name+second_iter_name_app]['rce_role'] == \
-                                    self.RCE_ROLES_FUNS[5]:  # Converger
-                                if analysis in coups_sorted and \
-                                        ((rce_graph.has_edge(analysis, iter_node_name+fourth_iter_name_app)
-                                          and new_xpath not in rce_graph.node[iter_node_name + second_iter_name_app]
-                                            ['xpaths'])
-                                         or not rce_graph.has_edge(analysis, iter_node_name + fourth_iter_name_app)):
-                                    if analysis not in iter_forwarded_inputs[iter_node_name]:
-                                        iter_forwarded_inputs[iter_node_name].append(str(analysis))
-                                        rce_graph.add_edge(analysis, iter_node_name + second_iter_name_app,
-                                                           forwarded_inputs=[analysis], xpaths=[])
-                                    if not direct_edge_allowed:
-                                        # If the direct edge is not allowed, then use forwarded input
-                                        if rce_graph.has_edge(iter_node_name + second_iter_name_app, target):
-                                            rce_graph[iter_node_name + second_iter_name_app][target]['forwarded_inputs'] \
-                                                .append(analysis)
-                                        else:
-                                            rce_graph.add_edge(iter_node_name + second_iter_name_app, target, xpaths=[],
-                                                               forwarded_inputs=[analysis])
-                                elif not direct_edge_allowed:
-                                    # Simply connect the final output of the converger to the target
-                                    rce_graph.add_edge(iter_node_name + fifth_iter_name_app, target, xpaths=[],
-                                                       forwarded_inputs = [iter_node_name + 'convvaluesXML'])
-                        # Remove edges between 'variable node-->target coupled function'
-                        rce_graph.remove_edge(var_node, target)
-                        # Remove variable node if it has no more outgoing edges
-                        if rce_graph.out_degree(var_node) == 0:
-                            rce_graph.remove_node(var_node)
-                    # Check if the target node of the variable node leads to an iof
-                    elif set([target]).intersection(iofs_sorted):
-                        # Determine XPath of the variable node
-                        if 'related_to_schema_node' in rce_graph.node[var_node]:
-                            new_xpath = rce_graph.node[var_node]['related_to_schema_node']
-                        else:
-                            new_xpath = var_node
-
-                        # Assess if a direct edge is allowed between the analyses
-                        if iter_is_nested and analysis in process_info['function_grouping'][iter_node_name] and \
-                                        target in process_info['function_grouping'][iter_node_name]:
-                            direct_edge_allowed = True
-                        elif not iter_is_nested or src in preiter_sorted+precoup_sorted:
-                            if iterative_nodes:
-                                if analysis in iofs_sorted or analysis in preiter_sorted+precoup_sorted:
-                                    direct_edge_allowed = True
-                                else:
-                                    direct_edge_allowed = False
-                            else:
-                                direct_edge_allowed = True
-                        else:
-                            direct_edge_allowed = False
-                        # Add direct edge between two coupled functions and the XPath in the pipeline (if iterator is
-                        # not nested or if both analysis are part of the same iterator)
-                        if rce_graph.has_edge(analysis, target) and direct_edge_allowed:
-                            rce_graph[analysis][target]['xpaths'].append(new_xpath)
-                        elif not rce_graph.has_edge(analysis, target) and direct_edge_allowed:
-                            rce_graph.add_edge(analysis, target, xpaths=[new_xpath])
-
-                        # If the xpath is not a coupling variable to be converged by the converger, then add the output
-                        # of the coupled function as forwarded input.
-                        if iterative_nodes and iter_node_name == self.CONVERGER_STRING:
-                            if analysis in coups_sorted and \
-                                    ((rce_graph.has_edge(analysis, iter_node_name + fourth_iter_name_app)
-                                      and new_xpath not in rce_graph.node[iter_node_name + second_iter_name_app]
-                                        ['xpaths'])
-                                     or not rce_graph.has_edge(analysis, iter_node_name + fourth_iter_name_app)):
-                                if analysis not in iter_forwarded_inputs[iter_node_name]:
-                                    iter_forwarded_inputs[iter_node_name].append(str(analysis))
-                                if rce_graph.has_edge(iter_node_name + fifth_iter_name_app, target):
-                                    rce_graph[iter_node_name + fifth_iter_name_app][target]['forwarded_inputs'].\
-                                        append(analysis)
-                                else:
-                                    rce_graph.add_edge(iter_node_name + second_iter_name_app, target,
-                                                       xpaths=[], forwarded_inputs=[analysis])
-                            else:
-                                # Add direct edge between converger result and iof and add the XPath in the pipeline
-                                if rce_graph.has_edge(iter_node_name + fifth_iter_name_app, target):
-                                    rce_graph[iter_node_name + fifth_iter_name_app][target]['xpaths'].append(new_xpath)
-                                else:
-                                    rce_graph.add_edge(iter_node_name + fifth_iter_name_app, target, xpaths=[new_xpath])
-                        # Remove edges between 'variable node-->target MDA'
-                        rce_graph.remove_edge(var_node, target)
-                        # Remove variable node if it has no more outgoing edges
-                        if rce_graph.out_degree(var_node) == 0:
-                            rce_graph.remove_node(var_node)
-                    # Check if the target node of the variable node leads to a pre-coupling or pre-iterator function
-                    elif set([target]).intersection(precoup_sorted+preiter_sorted):
-                        # Determine XPath of the variable node
-                        if 'related_to_schema_node' in rce_graph.node[var_node]:
-                            new_xpath = rce_graph.node[var_node]['related_to_schema_node']
-                        else:
-                            new_xpath = var_node
-
-                        # Add direct edge between two coupled functions and the XPath in the pipeline
-                        if rce_graph.has_edge(analysis, target):
-                            rce_graph[analysis][target]['xpaths'].append(new_xpath)
-                        elif not rce_graph.has_edge(analysis, target):
-                            rce_graph.add_edge(analysis, target, xpaths=[new_xpath])
-                        # Remove edges between 'variable node-->target'
-                        rce_graph.remove_edge(var_node, target)
-                        # Remove variable node if it has no more outgoing edges
-                        if rce_graph.out_degree(var_node) == 0:
-                            rce_graph.remove_node(var_node)
-
-        # ------------------------------------------------------------------------------------------------------------ #
-        #                                     STEP 5: Incoming Coordinator edges                                       #
-        # ------------------------------------------------------------------------------------------------------------ #
-        # Handle the incoming edges of the Coordinator node and combine them in the COOR-in node.
-
-        if not self.DOE_STRING in iterative_nodes:
-            # Add COOR-in block
-            rce_graph.insert_node_on_diagonal(coor_lab + '-in', 1 + len(iterative_nodes),
-                                              {'category': 'function',
-                                               'rce_role': self.RCE_ROLES_FUNS[1],  # XML Merger
-                                               'shape': '8',
-                                               'label': coor_lab + '-in',
-                                               'level': None,
-                                               'xpaths': []})
-            # Add new node grouping for COOR-in
-            node_grouping[coor_lab].append(coor_lab + '-in')
-
-            # Loop over each incoming edge to the Coordinator node
-            in_edges_coordinator = rce_graph.in_edges(self.COORDINATOR_STRING)
-            for (u, v) in in_edges_coordinator:
-                # Add XPath of the node to the xpath attribute of the INI-in node
-                if 'related_to_schema_node' in rce_graph.node[u]:
-                    new_xpath = rce_graph.node[u]['related_to_schema_node']
-                else:
-                    new_xpath = u
-                rce_graph.node[coor_lab + '-in']['xpaths'].append(new_xpath)
-
-                # Remove edge between Coordinator and variable
-                rce_graph.remove_edge(u, v)
-
-                # Loop over incoming edges of the node, connect COOR-in to right function, remove edge between variable
-                # and function
-                in_edges = rce_graph.in_edges(u)
-                for (w, uc) in in_edges:
-                    # Determine the iterator associated with the analysis
-                    iter_node_name = None
-                    iterator_is_nested = False
-                    if iterative_nodes:
-                        for iterator, analyses in process_info['function_grouping'].iteritems():
-                            if w in analyses:
-                                iter_node_name = iterator
-                                break
-                            elif w == iterator:
-                                iter_node_name = iterator
-                                break
-                        assert iter_node_name, 'The right iterator could not be found.'
-
-                        # Determine if the iterator found is nested
-                        iterator_is_nested = False if (
-                            iter_node_name in process_info['iter_nesting'] or not process_info['iter_nesting']) else True
-
-                        # If the iterator is nested, then determine the top-level iterator
-                        if iterator_is_nested:
-                            top_level_iterator = next((top_level_iter for top_level_iter, nested_iters in
-                                                   process_info['iter_nesting'].items() if
-                                                   iter_node_name in nested_iters), None)
-                            assert top_level_iterator, 'The right top level iterator could not be found.'
-
-
-                    # Select the right source node for the edge based on whether node is part of iterative element
-                    if 'architecture_role' in rce_graph.node[u]:
-                        if rce_graph.node[u]['architecture_role'] in get_list_entries(self.ARCHITECTURE_ROLES_VARS,1,4,5):
-                        # final coupling variable, final design variable, final output variable
-                            if iterative_nodes:
-                                if not iterator_is_nested:
-                                    source_edge = iter_node_name + fifth_iter_name_app
-                                else:
-                                    source_edge = top_level_iterator + second_iter_name_app
-                            else:
-                                source_edge = w
-                        else:
-                            source_edge = w
-                    else:
-                        # Handling of regular outputs from nested functions
-                        if iterative_nodes and w in coups_sorted:
-                            if not iterator_is_nested:
-                                source_edge = iter_node_name + fifth_iter_name_app
-                            else:
-                                source_edge = top_level_iterator + second_iter_name_app
-                        else:
-                            source_edge = w
-
-                    # Check if the variable is an xpath or forwarded_input
-                    if iterative_nodes:
-                        if w in coups_sorted:
-                            if ((rce_graph.has_edge(w, iter_node_name + fourth_iter_name_app)
-                                  and new_xpath not in rce_graph.node[iter_node_name + second_iter_name_app]['xpaths'])
-                                 or not rce_graph.has_edge(w, iter_node_name + fourth_iter_name_app)):
-                                forwarded_input = w if source_edge != iter_node_name + fifth_iter_name_app else None
-                                new_xpath = None
-                                if iterator_is_nested:
-                                    rce_graph.node[top_level_iterator+second_iter_name_app]['forwarded_inputs'].append(w)
-                                    # N.B. This inefficient method of combining edge attributes is unfortunately necessary.
-                                    rce_graph[coor_lab+'-start-'+iter_node_name][top_level_iterator+second_iter_name_app]['forwarded_inputs'] \
-                                        = rce_graph[coor_lab+'-start-' + iter_node_name][top_level_iterator + second_iter_name_app]['forwarded_inputs'] + [w]
-                            elif new_xpath in rce_graph.node[iter_node_name + second_iter_name_app]['xpaths'] and \
-                                    iterator_is_nested:
-                                forwarded_input = iter_node_name + 'convvaluesXML'
-                                new_xpath = None
-                        elif w in opfs_sorted and w != self.CONSCONS_STRING:
-                            forwarded_input = w
-                            new_xpath = None
-                            source_edge = iter_node_name + second_iter_name_app
-                            # Add analysis to forwarded_inputs
-                            if w not in iter_forwarded_inputs[iter_node_name]:
-                                iter_forwarded_inputs[iter_node_name].append(w)
-                            # Add or enrich edge between analysis and Optimizer
-                            if rce_graph.has_edge(w, iter_node_name + second_iter_name_app) \
-                                    and w not in rce_graph[w][iter_node_name + second_iter_name_app]['forwarded_inputs']:
-                                rce_graph[w][iter_node_name + second_iter_name_app]['forwarded_inputs'].append(w)
-                            else:
-                                rce_graph.add_edge(w, iter_node_name + second_iter_name_app,
-                                                   xpaths=[], forwarded_inputs=[w])
-                        else:
-                            forwarded_input = None
-                    else:
-                        forwarded_input = None
-
-                    # Add xpaths or forwarded_inputs to edge (also take nested functions into account)
-                    if rce_graph.has_edge(source_edge, coor_lab + '-in'):
-                        if new_xpath:
-                            rce_graph[source_edge][coor_lab + '-in']['xpaths'].append(new_xpath)
-                        elif forwarded_input and not iterator_is_nested:
-                            rce_graph[source_edge][coor_lab + '-in']['forwarded_inputs'].append(forwarded_input)
-                        elif forwarded_input and iterator_is_nested:
-                            # TODO: MAKE NEW FUNCTION TO ADD OR EXTEND EDGE
-                            if rce_graph.has_edge(iter_node_name, top_level_iterator+second_iter_name_app) and \
-                                    not 'convvaluesXML' in forwarded_input:
-                                rce_graph[iter_node_name][top_level_iterator+second_iter_name_app]['forwarded_inputs'].\
-                                    extend([forwarded_input])
-                            elif not 'convvaluesXML' in forwarded_input:
-                                rce_graph.add_edge(iter_node_name, top_level_iterator+second_iter_name_app, xpaths=[],
-                                                   forwarded_inputs=[forwarded_input])
-                            if rce_graph.has_edge(top_level_iterator + second_iter_name_app, coor_lab + '-in'):
-                                rce_graph[top_level_iterator + second_iter_name_app][coor_lab + '-in']['forwarded_inputs'].\
-                                    extend([forwarded_input])
-                            else:
-                                rce_graph.add_edge(top_level_iterator + second_iter_name_app, coor_lab + '-in', xpaths=[],
-                                               forwarded_inputs=[forwarded_input])
-                    elif not rce_graph.has_edge(source_edge, coor_lab + '-in') and not iterator_is_nested:
-                        rce_graph.add_edge(source_edge, coor_lab + '-in', xpaths=[], forwarded_inputs=[])
-                        if new_xpath:
-                            rce_graph[source_edge][coor_lab + '-in']['xpaths'].extend([new_xpath])
-                        elif forwarded_input:
-                            rce_graph[source_edge][coor_lab + '-in']['forwarded_inputs'].extend([forwarded_input])
-                    elif not rce_graph.has_edge(source_edge, coor_lab + '-in') and iterator_is_nested:
-                        if new_xpath:
-                            rce_graph.add_edge(source_edge, coor_lab + '-in', xpaths=[new_xpath], forwarded_inputs=[])
-                        elif forwarded_input:
-                            # TODO: MAKE NEW FUNCTION TO ADD OR EXTEND EDGE
-                            if rce_graph.has_edge(iter_node_name, top_level_iterator+second_iter_name_app):
-                                rce_graph[iter_node_name][top_level_iterator+second_iter_name_app]['forwarded_inputs'].\
-                                    extend([forwarded_input])
-                            else:
-                                rce_graph.add_edge(iter_node_name, top_level_iterator+second_iter_name_app, xpaths=[],
-                                                   forwarded_inputs=[forwarded_input])
-                            if rce_graph.has_edge(top_level_iterator + second_iter_name_app, coor_lab + '-in'):
-                                rce_graph[top_level_iterator + second_iter_name_app][coor_lab + '-in']['forwarded_inputs'].\
-                                    extend([forwarded_input])
-                            else:
-                                rce_graph.add_edge(top_level_iterator + second_iter_name_app, coor_lab + '-in', xpaths=[],
-                                                   forwarded_inputs=[forwarded_input])
-                    rce_graph.remove_edge(w, uc)
-
-                # Remove variable node if has become a hole (no incoming and outgoing edges)
-                if rce_graph.in_degree(u) == 0 and rce_graph.out_degree(u) == 0:
-                    rce_graph.remove_node(u)
-
-        # Remove original Coordinator node and any sources
-        if self.DOE_STRING in iterative_nodes:
-            coor_sources = rce_graph.get_sources(self.COORDINATOR_STRING)
-            rce_graph.remove_nodes_from(coor_sources)
-        rce_graph.remove_node(self.COORDINATOR_STRING)
-
-        # ------------------------------------------------------------------------------------------------------------ #
-        #                                      STEP 6: Handle forwarded inputs                                         #
-        # ------------------------------------------------------------------------------------------------------------ #
-        # For certain aspects, the forwarded inputs still need to handled.
-
-        # STEP 5: handle forwarded inputs
-        if iter_forwarded_inputs:
-            for iterator, items in iter_forwarded_inputs.iteritems():
-                if items:
-                    rce_graph.node[iterator + second_iter_name_app]['forwarded_inputs'].extend(items)
-                    rce_graph.node[iterator + first_iter_name_app]['forwarded_inputs'].extend(items)
-                    rce_graph.edge[iterator + first_iter_name_app][iterator + second_iter_name_app]['forwarded_inputs']\
-                        = items
-                if not process_info['iter_nesting'] \
-                        and rce_graph.node[iterator+second_iter_name_app]['rce_role'] == self.RCE_ROLES_FUNS[5] and \
-                                items: # Test if non-nested architecture is used and if there are any forwarded inputs
-                    if not rce_graph.has_edge(iterator + second_iter_name_app, coor_lab + '-in'):
-                        rce_graph.add_edge(iterator + second_iter_name_app, coor_lab + '-in', forwarded_inputs=items,
-                                           xpaths=[])
-                    else:
-                         rce_graph[iterator + second_iter_name_app][coor_lab + '-in']['forwarded_inputs'].extend(items)
-
-        # ------------------------------------------------------------------------------------------------------------ #
-        #                  STEP 7: XML Mergers and transformation of functions to RCE components                       #
-        # ------------------------------------------------------------------------------------------------------------ #
-        # Check and add XML mergers and assign rce_roles to coupled functions
-
-        # First for MDA analyses and independent output functions
-        nodes_of_interest = preiter_sorted + precoup_sorted + postiter_sorted + coups_sorted + opfs_sorted + \
-                            iofs_sorted + [coor_lab + '-in'] + [iter_node_name + fourth_iter_name_app for
-                                                                iter_node_name in iterative_nodes]
-        if self.DOE_STRING in iterative_nodes:
-            nodes_of_interest.remove(coor_lab + '-in')
-        for node_of_interest in nodes_of_interest:
-            # Check incoming edges
-            node_in_degree = rce_graph.in_degree(node_of_interest)
-            indegree_limit = 1 if node_of_interest != self.CONSCONS_STRING else 2
-            reduced_xmls = 0 if node_of_interest != self.CONSCONS_STRING else 1
-            if node_in_degree > indegree_limit:
-                node_in_nodes = [e[0] for e in rce_graph.in_edges(node_of_interest)]
-                # Add XML Merger component
-                new_node = 'XMLM-' + rce_graph.node[node_of_interest]['label']
-                # Add new node to node grouping for each XML Merger
-                if node_of_interest == coor_lab+ '-in':
-                    node_grouping[coor_lab].append(new_node)
-                    additional_diag_pos = 1
-                elif fourth_iter_name_app in node_of_interest:
-                    node_grouping[node_of_interest.replace(fourth_iter_name_app, '')].append(new_node)
-                    additional_diag_pos = 1
-                else:
-                    node_grouping[node_of_interest].append(new_node)
-                    additional_diag_pos = 0
-                # Add forwarded inputs from coupled function if they are connected to the node of interest
-                linked_iter_nodes = set(iterative_nodes).\
-                    intersection(set([item[0] for item in rce_graph.in_edges(node_of_interest)]))
-                assert len(linked_iter_nodes) <= 1, \
-                    'Only maximum one iterative node can be linked to ' + coor_lab + '-in, for now.'
-                if len(linked_iter_nodes) == 1:
-                    iter_node_name = list(linked_iter_nodes)[0]
-                    if 'forwarded_inputs' in rce_graph[iter_node_name][node_of_interest]:
-                        number_of_xmls = node_in_degree + \
-                                         len(rce_graph[iter_node_name][node_of_interest][
-                                                 'forwarded_inputs']) - 1 - reduced_xmls
-                        forwarded_inputs = rce_graph[iter_node_name][node_of_interest]['forwarded_inputs']
-                    else:
-                        number_of_xmls = node_in_degree - reduced_xmls
-                        forwarded_inputs = []
-                else:
-                    number_of_xmls = node_in_degree - reduced_xmls
-                    forwarded_inputs = []
-                assert number_of_xmls < 11, 'The ' + str(node_of_interest) + \
-                                            '  XML PyMerger needs to merge more than 10 XML files.'
-                rce_graph.insert_node_on_diagonal(new_node,
-                                                  rce_graph.node[node_of_interest]['diagonal_position'] +
-                                                  additional_diag_pos,
-                                                  {'category': 'function',
-                                                   'rce_role': self.RCE_ROLES_FUNS[3],  # XML PyMerger
-                                                   'number_of_xmls': number_of_xmls,
-                                                   'in_nodes': node_in_nodes,
-                                                   'shape': 's',
-                                                   'label': new_node,
-                                                   'level': None,
-                                                   'xpaths': [],
-                                                   'forwarded_inputs': forwarded_inputs})
-                # Redirect incoming edges to XML Merger and connect XML Merger to the node_of_interest
-                item_in_edges = rce_graph.in_edges(node_of_interest)
-                for (source, mda_target) in item_in_edges:
-                    if not (node_of_interest == self.CONSCONS_STRING and third_iter_name_app in source):
-                        rce_graph.add_edge(source, new_node)
-                        rce_graph[source][new_node] = rce_graph[source][mda_target]
-                        rce_graph.remove_edge(source, mda_target)
-                        # Add edge between XML merger and coupled analysis node_of_interest
-                        if rce_graph.has_edge(new_node, mda_target):
-                            rce_graph[new_node][mda_target]['xpaths'].extend(rce_graph[source][new_node]['xpaths'])
-                            if 'forwarded_inputs' in rce_graph[source][new_node]:
-                                rce_graph[new_node][mda_target]['forwarded_inputs']. \
-                                    extend(rce_graph[source][new_node]['forwarded_inputs'])
-                        else:
-                            rce_graph.add_edge(new_node, mda_target, xpaths=[], forwarded_inputs=[])
-                            # N.B. Separation concerning xpath attribute is needed due to issues with edge attribute
-                            # copying
-                            rce_graph[new_node][mda_target]['xpaths'].extend(rce_graph[source][new_node]['xpaths'])
-                            if 'forwarded_inputs' in rce_graph[source][new_node]:
-                                rce_graph[new_node][mda_target]['forwarded_inputs']. \
-                                    extend(rce_graph[source][new_node]['forwarded_inputs'])
-                        rce_graph.node[new_node]['xpaths'].extend(rce_graph[source][new_node]['xpaths'])
-
-        # ------------------------------------------------------------------------------------------------------------ #
-        #                                       STEP 8: Output filters                                                 #
-        # ------------------------------------------------------------------------------------------------------------ #
-        # Add filters on the outputs of the executable blocks.
-        # Add an input provider node to collect all output filter json files
-        if add_output_filters:
-            # Determine filtered functions
-            filtered_functions = list(all_sorted)
-            if self.CONSCONS_STRING in filtered_functions:
-                filtered_functions.remove(self.CONSCONS_STRING)
-
-            # Add input provider for filter jsons
-            rce_graph.insert_node_on_diagonal(coor_lab + '-filters', 1,
-                                              {'category': 'function',
-                                               'rce_role': self.RCE_ROLES_FUNS[0],  # Input Provider
-                                               'shape': '8',
-                                               'label': coor_lab + '-filters',
-                                               'level': None,
-                                               'diagonal_position': 1,
-                                               'xpaths': [],
-                                               'coor_xml_filename': None,
-                                               'input_filenames': [coor_lab + '-' +
-                                                                   self.UXPFILTER_PREFIX + func_name + '.json'
-                                                                   for
-                                                                   func_name in filtered_functions]})
-            node_grouping[coor_lab].append(coor_lab + '-filters')
-
-            # Add filter blocks
-            for func in filtered_functions:
-                filter_name = self.UXPFILTER_PREFIX + func
-                rce_graph.insert_node_on_diagonal(filter_name,
-                                                  rce_graph.node[func]['diagonal_position'] + 1,
-                                                  {'category': 'function',
-                                                   'rce_role': self.RCE_ROLES_FUNS[8],  # UXPath Filter
-                                                   'shape': '8',
-                                                   'label': filter_name,
-                                                   'level': None,
-                                                   'diagonal_position': rce_graph.node[func][
-                                                                            'diagonal_position'] + 1,
-                                                   'filter_json_filename': self.UXPFILTER_PREFIX + func + '.json',
-                                                   'rce_metadata': self.UXPFILTER_RCE_INFO['rce_info']})
-                # Add forwarded inputs from function and remove from normal function
-                if 'forwarded_inputs' in rce_graph.node[func]:
-                    rce_graph.node[filter_name]['forwarded_inputs'] = [self.UXPFILTER_PREFIX + fi for fi
-                                                                       in rce_graph.node[func][
-                                                                           'forwarded_inputs']]
-                    rce_graph.node[func]['forwarded_inputs'] = []
-                rce_graph.node[filter_name]['rce_metadata']['component']['name'] = filter_name
-                node_grouping[func].append(filter_name)
-                # Reconnect filter function and actual function
-                for target in rce_graph.get_targets(func):
-                    # Connect targets of function from filter
-                    rce_graph.add_edge(filter_name, target, dict(rce_graph[func][target]))
-                    # Remove original edges
-                    rce_graph.remove_edge(func, target)
-                    # Rename forwarded inputs
-                    if 'forwarded_inputs' in rce_graph[filter_name][target]:
-                        rce_graph[filter_name][target]['forwarded_inputs'] = [self.UXPFILTER_PREFIX + fi
-                                                                              for fi in
-                                                                              rce_graph[filter_name][
-                                                                                  target][
-                                                                                  'forwarded_inputs']]
-                # Add direct edge between function and filter
-                function_xpaths = set([])
-                for target in self.get_targets(func):
-                    if 'related_to_schema_node' in self.node[target]:
-                        function_xpaths.update([self.node[target]['related_to_schema_node']])
-                    else:
-                        function_xpaths.update([target])
-                function_xpaths = list(function_xpaths)
-                rce_graph.add_edge(func, filter_name, xpaths=function_xpaths)
-                # Add direct edge between input provider and filter
-                rce_graph.add_edge(coor_lab + '-filters', filter_name,
-                                   coor_json_filter=coor_lab + '-filter_' + func,
-                                   xpaths=['FileTransfer'])
-
-                # Adjust name of forwarded_inputs in the iterative blocks
-                for iterative_node in iterative_nodes:
-                    iterative_node_group = node_grouping[iterative_node]
-                    for node in iterative_node_group:
-                        if 'forwarded_inputs' in rce_graph.node[node]:
-                            if func in rce_graph.node[node]['forwarded_inputs']:
-                                rce_graph.node[node]['forwarded_inputs'].remove(func)
-                                rce_graph.node[node]['forwarded_inputs'].append(
-                                    self.UXPFILTER_PREFIX + func)
-
-                # Adjust name of forwarded_inputs in the edges
-                for (u, v, d) in rce_graph.edges_iter(data=True):
-                    if 'forwarded_inputs' in d:
-                        if func in d['forwarded_inputs']:
-                            d['forwarded_inputs'].remove(func)
-                            d['forwarded_inputs'].append(self.UXPFILTER_PREFIX + func)
-
-        # ------------------------------------------------------------------------------------------------------------ #
-        #                                   STEP 9: Transform to CPACS tools                                           #
-        # ------------------------------------------------------------------------------------------------------------ #
-        for func_node in all_sorted:
-            if not 'merge_info' in rce_graph.node[func_node]:
-                if func_node != self.CONSCONS_STRING:
-                    rce_graph.node[func_node]['rce_role'] = self.RCE_ROLES_FUNS[4]  # CPACS Tool
-                    info_file = rce_graph.node[func_node]['name'] + '-info.json'
-                    file_path = self.graph['kb_path'] + '/' + info_file
-                    if os.path.exists(file_path):
-                        with open(file_path) as data_file:
-                            data = json.load(data_file)
-                        rce_graph.node[func_node]['rce_metadata'] = data['rce_info']
-                        if 'executionMode' in data['rce_info']:
-                            if data['rce_info']['executionMode'] == 'use_tool_mode':
-                                rce_graph.node[func_node]['rce_metadata']['executionMode'] = rce_graph.node[func_node]['mode']
-                            else:
-                                raise AssertionError('Invalid executionMode given in rce_info.')
-                        else:
-                            rce_graph.node[func_node]['rce_metadata']['executionMode'] = None
-                    else:
-                        raise IOError('Could not find tool info file: %s' % file_path)
-                elif func_node == self.CONSCONS_STRING:
-                    # Determine the iterator associated with the analysis
-                    for iterator, analyses in process_info['function_grouping'].iteritems():
-                        if func_node in analyses:
-                            iter_node_name = iterator
-                            break
-                    rce_graph.node[func_node]['rce_role'] = self.RCE_ROLES_FUNS[7] # Consistency constraint function
-                    rce_graph.node[func_node]['rce_metadata'] = self.CONSCONS_RCE_INFO['rce_info']
-                    # Add xpaths of consistency constraint variables to fourth iter node and edge between fourth and second
-                    # N.B. This inefficient method of combining two lists is required, since there is a problem with using
-                    # list operations on networkx attributes
-                    rce_graph[iter_node_name + fourth_iter_name_app][iter_node_name + second_iter_name_app]['xpaths'] = \
-                        rce_graph[iter_node_name + fourth_iter_name_app][iter_node_name + second_iter_name_app]['xpaths']+ \
-                        self.node[func_node]['consistency_nodes']
-            else:
-                merge_type = rce_graph.node[func_node]['merge_info']['merge_type']
-                if rce_graph.node[func_node]['merge_info']['merge_type'] == 'sequential':
-                    # Get the function order and subgraph
-                    func_order = rce_graph.node[func_node]['merge_info']['merge_order']
-                    subgraph = rce_graph.node[func_node]['subgraph']
-                    for idx, merged_func in enumerate(func_order):
-                        # Add function
-                        rce_graph.insert_node_on_diagonal(merged_func, rce_graph.node[func_node]['diagonal_position'],
-                                                          attr_dict=dict(rce_graph.node[func_node]['contraction'][merged_func]))
-                        rce_graph.node[merged_func]['architecture_role'] = str(rce_graph.node[func_node]['architecture_role'])
-                        rce_graph.node[merged_func]['rce_role'] = self.RCE_ROLES_FUNS[4]  # CPACS Tool
-                        # Add function to the node grouping
-                        node_grouping[func_node].append(merged_func)
-                        # Add rce_metadata to the block
-                        info_file = rce_graph.node[merged_func]['name'] + '-info.json'
-                        file_path = self.graph['kb_path'] + '/' + info_file
-                        if os.path.exists(file_path):
-                            with open(file_path) as data_file:
-                                data = json.load(data_file)
-                            rce_graph.node[merged_func]['rce_metadata'] = data['rce_info']
-                        else:
-                            raise IOError('Could not find tool info file: %s' % file_path)
-                        if 'executionMode' in data['rce_info']:
-                            if data['rce_info']['executionMode'] == 'use_tool_mode':
-                                rce_graph.node[merged_func]['rce_metadata']['executionMode'] = subgraph.node[merged_func]['mode']
-                            else:
-                                raise AssertionError('Invalid executionMode given in rce_info.')
-                        else:
-                            rce_graph.node[merged_func]['rce_metadata']['executionMode'] = None
-                        # For first function, connect incoming edges as for merged node
-                        if idx == 0:
-                            # Copy edges
-                            for edge in rce_graph.in_edges_iter(func_node, data=True):
-                                rce_graph.add_edge(edge[0], merged_func, edge[2])
-                        # For last function, connect outgoing edges as for merged node
-                        elif idx == len(func_order)-1:
-                            # Copy edges
-                            for edge in rce_graph.out_edges_iter(func_node, data=True):
-                                rce_graph.add_edge(merged_func, edge[1], edge[2])
-                            # Make edge with previous function
-                            rce_graph.add_edge(func_order[idx - 1], merged_func,
-                                               xpaths=['internalCoupling'])  # TODO: use subgraph for full data
-                        # For other functions, just connect the function to the next one in the list
-                        else:
-                            # Make edge with previous function
-                            rce_graph.add_edge(func_order[idx-1], merged_func,
-                                               xpaths=['internalCoupling'])  # TODO: use subgraph for full data
-                    # Remove the original
-                    rce_graph.remove_node_from_diagonal(func_node)
-                    node_grouping[func_node].remove(func_node)
-                else:
-                    raise AssertionError('Invalid merge_type %s found.' % merge_type)
-
-        # ------------------------------------------------------------------------------------------------------------ #
-        #                                  STEP 10: Check for constant inputs                                          #
-        # ------------------------------------------------------------------------------------------------------------ #
-        # Loop over all edges and check if there are cases where the input of the edge should be constant
-        all_edges = rce_graph.edges()
-        for edge in all_edges:
-            # For connections between input providers and XML PyMergers the input of the XML PyMerger should be made
-            # constant
-            if rce_graph.node[edge[0]]['rce_role'] == self.RCE_ROLES_FUNS[0] and \
-                            rce_graph.node[edge[1]]['rce_role'] == self.RCE_ROLES_FUNS[3]:  # Input Pr. or XML PyMerger
-                if 'rce_specific' in edge:
-                    rce_graph[edge[0]][edge[1]]['rce_specific'].append('Constant input')
-                else:
-                    rce_graph[edge[0]][edge[1]]['rce_specific'] = ['Constant input']
-            # For connections between pre-iter functions and XML PyMergers the input of the XML PyMerger should be made
-            # constant
-            if rce_graph.node[edge[0]]['rce_role'] in get_list_entries(self.RCE_ROLES_FUNS, 4, 8) and \
-                            rce_graph.node[edge[1]]['rce_role'] == self.RCE_ROLES_FUNS[3]: # CPACS tool / UXPath filter / XML PyMerger
-                rce_role = rce_graph.node[edge[0]]['rce_role']
-                if rce_role == self.RCE_ROLES_FUNS[4]: # CPACS tool
-                    analysis_name = rce_graph.node[edge[0]]['label']
-                elif rce_role == self.RCE_ROLES_FUNS[8]: # UXPath filter
-                    analysis_name = rce_graph.node[edge[0]]['label'].replace(self.UXPFILTER_PREFIX,'')
-                if analysis_name in precoup_sorted+preiter_sorted:
-                    if 'rce_specific' in edge:
-                        rce_graph[edge[0]][edge[1]]['rce_specific'].append('Constant input')
-                    else:
-                        rce_graph[edge[0]][edge[1]]['rce_specific'] = ['Constant input']
-            # For nested loops the input from outside a nested loop into a PyMerger should be made constant
-            if rce_graph.node[edge[1]]['rce_role'] == self.RCE_ROLES_FUNS[3]:  # XML PyMerger
-                analysis_name = rce_graph.node[edge[1]]['label'].replace('XMLM-','')
-                source_name = rce_graph.node[edge[0]]['label'].replace('XMLM-','').replace(self.UXPFILTER_PREFIX,'')
-                if analysis_name in nested_functions:
-                    # Determine the top-level iterator associated with the nested analysis
-                    nested_iter = next((nested_iter for nested_iter, analyses in
-                                        process_info['function_grouping'].items() if analysis_name in analyses), None)
-                    top_level_iter = next((top_level_iter for top_level_iter, nested_iters in
-                                           process_info['iter_nesting'].items() if nested_iter in nested_iters), None)
-                    if top_level_iter in rce_graph.node[edge[0]]['label'] or \
-                                    source_name in preiter_sorted+precoup_sorted+postiter_sorted:
-                        if 'rce_specific' in edge:
-                            rce_graph[edge[0]][edge[1]]['rce_specific'].append('Constant input')
-                        else:
-                            rce_graph[edge[0]][edge[1]]['rce_specific'] = ['Constant input']
-
-        # ------------------------------------------------------------------------------------------------------------ #
-        #                                        STEP 11: Final checks                                                 #
-        # ------------------------------------------------------------------------------------------------------------ #
-        # Add node grouping as graph attribute
-        rce_graph.graph['node_grouping'] = node_grouping
-
-        # Check diagonal positions
-        number_of_nodes = rce_graph.number_of_nodes()
-        diag_pos_nodes = [rce_graph.node[n]['diagonal_position'] for n in rce_graph.nodes()]
-        list_diag_pos = [i for i in range(0, number_of_nodes)]
-        for pos in list_diag_pos:
-            assert pos in diag_pos_nodes, 'Diagonal position ' + str(pos) + ' is missing in the RCE graph.'
-
-        logger.info('RCE graph successfully created.')
-        return rce_graph