diff --git a/examples/knowledgebases/ssbj/__cmdows__SSBJ.xml b/examples/knowledgebases/ssbj/__cmdows__SSBJ.xml
index 503ade6a418a581cc17a6e116d64104c597718dc..2b51a758849ff41f75070277234d24740a1a7120 100644
--- a/examples/knowledgebases/ssbj/__cmdows__SSBJ.xml
+++ b/examples/knowledgebases/ssbj/__cmdows__SSBJ.xml
@@ -97,7 +97,7 @@
                   <softwareRequirement>Python 2.7.11 or higher installed</softwareRequirement>
                   <softwareRequirement>kadmos Python package version 0.8 or higher installed</softwareRequirement>
                 </softwareRequirements>
-                <command>cd %PROJECTDIR%\SSBJ\n"ssbjkadmos\tools\aerodynamics\structures.py"  -i "cpacsInputUpdated.xml" -o "cpacsOutput.xml"\necho doing some analysis\ncopy %PROJECTDIR%\SSBJ\cpacsOutput.xml %METHODDIR%\cpacsOutput.xml</command>
+                <command>cd %PROJECTDIR%\SSBJ\n"ssbjkadmos\tools\structures\Structures.py"  -i "cpacsInputUpdated.xml" -o "cpacsOutput.xml"\necho doing some analysis\ncopy %PROJECTDIR%\SSBJ\cpacsOutput.xml %METHODDIR%\cpacsOutput.xml</command>
                 <integrationPlatform>Optimus</integrationPlatform>
               </executionDetails>
             </localComponentInfo>
@@ -146,7 +146,7 @@
                   <softwareRequirement>Python 2.7.11 or higher installed</softwareRequirement>
                   <softwareRequirement>kadmos Python package version 0.8 or higher installed</softwareRequirement>
                 </softwareRequirements>
-                <command>cd %PROJECTDIR%\SSBJ\n"ssbjkadmos\tools\aerodynamics\aerodynamics.py"  -i "cpacsInputUpdated.xml" -o "cpacsOutput.xml"\necho doing some analysis\ncopy %PROJECTDIR%\SSBJ\cpacsOutput.xml %METHODDIR%\cpacsOutput.xml</command>
+                <command>cd %PROJECTDIR%\SSBJ\n"ssbjkadmos\tools\aerodynamics\Aerodynamics.py"  -i "cpacsInputUpdated.xml" -o "cpacsOutput.xml"\necho doing some analysis\ncopy %PROJECTDIR%\SSBJ\cpacsOutput.xml %METHODDIR%\cpacsOutput.xml</command>
                 <integrationPlatform>Optimus</integrationPlatform>
               </executionDetails>
             </localComponentInfo>
@@ -195,7 +195,7 @@
                   <softwareRequirement>Python 2.7.11 or higher installed</softwareRequirement>
                   <softwareRequirement>kadmos Python package version 0.8 or higher installed</softwareRequirement>
                 </softwareRequirements>
-                <command>cd %PROJECTDIR%\SSBJ\n"ssbjkadmos\tools\aerodynamics\propulsion.py"  -i "cpacsInputUpdated.xml" -o "cpacsOutput.xml"\necho doing some analysis\ncopy %PROJECTDIR%\SSBJ\cpacsOutput.xml %METHODDIR%\cpacsOutput.xml</command>
+                <command>cd %PROJECTDIR%\SSBJ\n"ssbjkadmos\tools\propulsion\Propulsion.py"  -i "cpacsInputUpdated.xml" -o "cpacsOutput.xml"\necho doing some analysis\ncopy %PROJECTDIR%\SSBJ\cpacsOutput.xml %METHODDIR%\cpacsOutput.xml</command>
                 <integrationPlatform>Optimus</integrationPlatform>
               </executionDetails>
             </localComponentInfo>
@@ -244,7 +244,7 @@
                   <softwareRequirement>Python 2.7.11 or higher installed</softwareRequirement>
                   <softwareRequirement>kadmos Python package version 0.8 or higher installed</softwareRequirement>
                 </softwareRequirements>
-                <command>cd %PROJECTDIR%\SSBJ\n"ssbjkadmos\tools\aerodynamics\performance.py"  -i "cpacsInputUpdated.xml" -o "cpacsOutput.xml"\necho doing some analysis\ncopy %PROJECTDIR%\SSBJ\cpacsOutput.xml %METHODDIR%\cpacsOutput.xml</command>
+                <command>cd %PROJECTDIR%\SSBJ\n"ssbjkadmos\tools\performance\Performance.py"  -i "cpacsInputUpdated.xml" -o "cpacsOutput.xml"\necho doing some analysis\ncopy %PROJECTDIR%\SSBJ\cpacsOutput.xml %METHODDIR%\cpacsOutput.xml</command>
                 <integrationPlatform>Optimus</integrationPlatform>
               </executionDetails>
             </localComponentInfo>
diff --git a/examples/knowledgebases/ssbj/create_cmdows_file.py b/examples/knowledgebases/ssbj/create_cmdows_file.py
index a0baf8cde66b248b6d6b9cb809d6afafa0220759..79cc1ed8fe35e593fe362de7d4d321dc0ff99d0b 100644
--- a/examples/knowledgebases/ssbj/create_cmdows_file.py
+++ b/examples/knowledgebases/ssbj/create_cmdows_file.py
@@ -47,7 +47,7 @@ for dc in dcs:
                                     operating_system='Windows',
                                     integration_platform='Optimus',
                                     command='cd %PROJECTDIR%\SSBJ\\n'
-                                            '"ssbjkadmos\\tools\\aerodynamics\\{}.py"  -i "cpacsInputUpdated.xml" -o "cpacsOutput.xml"\\n'
+                                            '"ssbjkadmos\\tools\\{}\\{}.py"  -i "cpacsInputUpdated.xml" -o "cpacsOutput.xml"\\n'
                                             'echo doing some analysis\\n'
                                             'copy %PROJECTDIR%\\SSBJ\\cpacsOutput.xml %METHODDIR%\\cpacsOutput.xml'.format(dc.lower(), dc),
                                     description='Details for the command line execution of the {} Python tool in Windows using an Optimus integration.'.format(dc),
diff --git a/kadmos/vistoms/examples/sellar_problem/VISTOMS_interactive/tmp_01.kdms b/kadmos/vistoms/examples/sellar_problem/VISTOMS_interactive/tmp_01.kdms
index a3c29d5b7d5330fbfa723027bdcc751f4ec49eae..9f52a17481dc20c331411df904a0cc41f31408c7 100644
Binary files a/kadmos/vistoms/examples/sellar_problem/VISTOMS_interactive/tmp_01.kdms and b/kadmos/vistoms/examples/sellar_problem/VISTOMS_interactive/tmp_01.kdms differ
diff --git a/kadmos/vistoms/interface_vistoms.py b/kadmos/vistoms/interface_vistoms.py
index f4268e3121695e63947b96060fcff41101dfde8f..1c8350156e7e7a7223053bc8e6f06f94a4af5418 100644
--- a/kadmos/vistoms/interface_vistoms.py
+++ b/kadmos/vistoms/interface_vistoms.py
@@ -1,14 +1,26 @@
+import ast
+import json
+import logging
+import shutil
+import subprocess
 import tempfile
 import os
+import zipfile
+from copy import deepcopy
+from shutil import copyfile
 
-from flask import Flask, request, render_template
+from flask import Flask, request, render_template, jsonify
 
+from kadmos.cmdows.cmdows import find_cmdows_file
 from kadmos.graph import *
 from kadmos.graph.mixin_vistoms import vistoms_start
 from kadmos.vistoms.vistoms import run_vistoms
 
+# Folder and file settings
+UPLOAD_FOLDER = ''
+TEMP_FILE = 'tmp'
 
-def interface(debug=False, tempdir=None):
+def interface(debug=True, tempdir=None):
 
     # Initial settings
     app = Flask(__name__)
@@ -32,11 +44,21 @@ def interface(debug=False, tempdir=None):
     @app.route("/", methods=['POST'])
     @app.route('/examples/', defaults={'path': ''})
     @app.route('/examples/<path:path>')
-    def upload(path=None):
+    def upload(path=None, error=None, message=None):
 
         # Start the vistoms app with an empty session
         if path is None:
-            run_vistoms(open_vistoms=False)
+            # Check if error or message is send
+            if request.values.get('error', False) and error is None:
+                error = request.values['error']
+            if request.values.get('message', False) and message is None:
+                message = request.values['message']
+            global UPLOAD_FOLDER
+            logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.DEBUG)
+
+            # Create temporary directory
+            UPLOAD_FOLDER = tempfile.mkdtemp()
+            return render_template('VISTOMS.html', new=0, error=error, message=message)
 
         # Start the vistoms app with files loaded depending on path
         else:
@@ -68,5 +90,1510 @@ def interface(debug=False, tempdir=None):
     def acknowledgements():
         return render_template('acknowledgements.html', page='acknowledgements')
 
+    @app.route('/kadmosUploadFile', methods=['GET', 'POST'])
+    def kadmosUploadFile():
+        """
+            Function uploads a file to the temp folder and returns the graph information to VISTOMS
+
+            :return: VISTOMS json data with graph information
+        """
+        try:
+            if request.method == 'POST':
+                # get request form
+                fileType = request.form['fileType']
+                newGraphID = request.form['newGraphID']
+                uploaded_files = request.files.getlist("file[]")
+
+                number_of_files = len(uploaded_files)
+                if number_of_files > 2:
+                    return ("ERROR: Max. number of files that can be uploaded is 2!")
+
+                mpgFile = []
+                dgFile = []
+                for file in uploaded_files:
+                    if "_mpg" in file.filename:
+                        mpgFile = file
+                    else:
+                        dgFile = file
+
+                # check if the post request has the file part
+                if 'file[]' not in request.files:
+                    return ("ERROR: No file part!")
+
+                # if user does not select file, browser also
+                # submit a empty part without filename
+                if dgFile.filename == '':
+                    return ("ERROR: No file part!")
+                if dgFile:
+                    # Check if the right filetypes were chosen
+                    if fileType == 'CMDOWS file' and dgFile.filename.rsplit('.', 1)[1].lower() != "xml":
+                        return ("ERROR: Wrong file type! Please use a valid CMDOWS file")
+                    elif fileType == 'KDMS file(s)' and dgFile.filename.rsplit('.', 1)[1].lower() != "kdms":
+                        return ("ERROR: Wrong file type! Please use a valid KDMS file")
+                    elif fileType == 'Database' and dgFile.filename.rsplit('.', 1)[1].lower() != "zip":
+                        return ("ERROR: Wrong file type! Please use a valid zip file")
+
+                    if not os.path.exists(UPLOAD_FOLDER):
+                        os.makedirs(UPLOAD_FOLDER)
+
+                    database_dir = ""
+                    if fileType == 'Database':
+                        database_dir = os.path.join(UPLOAD_FOLDER, 'database_tmp')
+                        zip_ref = zipfile.ZipFile(file, 'r')
+                        zip_ref.extractall(database_dir)
+                        zip_ref.close()
+                        file_list = []
+                        for file in os.listdir(database_dir):
+                            file_list.append(os.path.join(database_dir, file))
+                        cmdows_file = find_cmdows_file(file_list)
+                        graphFileName = cmdows_file
+                    else:
+                        graphFileName = os.path.join(UPLOAD_FOLDER, dgFile.filename)
+                        dgFile.save(os.path.join(UPLOAD_FOLDER, dgFile.filename))
+
+                    loaded_graph = load(graphFileName, file_check_critical=False)
+                    # Remove the uploaded file (and if existing, database directory) from the temp folder
+                    os.remove(graphFileName)
+                    if os.path.exists(database_dir):
+                        shutil.rmtree(database_dir)
+
+                    if isinstance(loaded_graph, tuple):
+                        graph = loaded_graph[0]
+                        mpg = loaded_graph[1]
+                    elif mpgFile:
+                        # Check if the right filetype was chosen
+                        if mpgFile.filename.rsplit('.', 1)[1].lower() != "kdms":
+                            return ("ERROR: Wrong file type! Please use a valid KDMS file")
+                        graph = loaded_graph
+                        mpgFileName = mpgFile.filename
+                        mpgFile.save(os.path.join(UPLOAD_FOLDER, mpgFileName))
+                        mpg = load(os.path.join(UPLOAD_FOLDER, mpgFileName), file_check_critical=True)
+                        # Remove the uploaded file from the temp folder
+                        os.remove(os.path.join(UPLOAD_FOLDER, mpgFileName))
+                    else:
+                        graph = loaded_graph
+                        mpg = None
+
+                    # save the graph as kdms file in temp folder
+                    graph.save(os.path.join(UPLOAD_FOLDER, TEMP_FILE + '_' + newGraphID + '.kdms'), file_type='kdms',
+                               graph_check_critical=False, mpg=mpg)
+
+                    # Use function order for VISTOMS if it is available in the graph information
+                    function_order = None
+                    if graph.graph_has_nested_attributes('problem_formulation', 'function_order') and mpg == None:
+                        function_order = graph.graph['problem_formulation']['function_order']
+
+                    # Add the graph with the updated function order to VISTOMS
+                    newVistomsData = graph.vistoms_add_json(graph_id=newGraphID, function_order=function_order, mpg=mpg)
+
+                    return newVistomsData
+
+            return ("ERROR: File type " + dgFile.filename.rsplit('.', 1)[1].lower() + " not allowed!")
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    @app.route('/kadmosExportAllGraphs', methods=['POST'])
+    def kadmosExportAllGraphs():
+        """
+           Function exports all graphs to a folder as CMDOWS or KDMS files
+
+           :param path: the path of the folder, the files are exported to
+           :return: path
+        """
+        try:
+            # Get request form
+            path = os.path.join(request.form['path'], '')
+            fileType = request.form['fileType']
+
+            if not os.path.isdir(path):
+                os.makedirs(os.path.dirname(path))
+
+            for aFile in os.listdir(UPLOAD_FOLDER):
+                if aFile.endswith(".kdms"):
+                    fileName = aFile.split('.')[0]
+                    fileName_split = fileName.split('_')
+                    if "mpg" not in fileName_split and "backup" not in fileName_split:  # Do not loop through mpg files
+                        graphFileName = fileName + ".kdms"
+                        mpgFileName = fileName + "_mpg.kdms"
+                        if os.path.exists(os.path.join(UPLOAD_FOLDER, mpgFileName)):
+                            graph = load(os.path.join(UPLOAD_FOLDER, graphFileName), file_check_critical=False)
+                            mpg = load(os.path.join(UPLOAD_FOLDER, mpgFileName), file_check_critical=False)
+                        else:
+                            graph = load(os.path.join(UPLOAD_FOLDER, graphFileName), file_check_critical=False)
+                            mpg = None
+
+                        # Add problem function roles if they are not already existing
+                        if not hasattr(graph, 'name'):
+                            graph_name = fileName
+                        else:
+                            graph_name = graph.name
+                        # Add problem function roles if they are not already existing
+                        if isinstance(graph, FundamentalProblemGraph):
+                            if 'function_order' not in graph.graph['problem_formulation']:
+                                graph.assert_or_add_nested_attribute(['problem_formulation', 'function_order'],
+                                                                     None)
+                            if 'mdao_architecture' not in graph.graph['problem_formulation']:
+                                graph.assert_or_add_nested_attribute(['problem_formulation', 'mdao_architecture'],
+                                                                     'undefined')
+                            if 'allow_unconverged_couplings' not in graph.graph['problem_formulation']:
+                                graph.assert_or_add_nested_attribute(
+                                    ['problem_formulation', 'allow_unconverged_couplings'],
+                                    False)
+                            graph.add_function_problem_roles()
+
+                        if fileType == "CMDOWS files":
+                            file_type = "cmdows"
+                            file = graph_name + ".xml"
+                            # Save as CMDOWS file
+                            graph.save(os.path.join(UPLOAD_FOLDER, graph_name), file_type=file_type,
+                                       graph_check_critical=False, mpg=mpg)
+                            # Copy CMDOWS file from temporary folder to user's download folder
+                            copyfile(os.path.join(UPLOAD_FOLDER, file), os.path.join(path, file))
+                            # remove temporary CMDOWS file
+                            os.remove(os.path.join(UPLOAD_FOLDER, file))
+                        elif fileType == "KDMS files":
+                            file_type = "kdms"
+                            # Save as kdms file
+                            graph.save(os.path.join(UPLOAD_FOLDER, graph_name), file_type=file_type,
+                                       graph_check_critical=False, mpg=mpg)
+                            file = graph_name + ".kdms"
+                            mpgfile = graph_name + "_mpg.kdms"
+                            # Copy kdms file from temporary folder to user's download folder
+                            copyfile(os.path.join(UPLOAD_FOLDER, file), os.path.join(path, file))
+                            # remove temporary kdms file
+                            os.remove(os.path.join(UPLOAD_FOLDER, file))
+                            if os.path.exists(os.path.join(UPLOAD_FOLDER, mpgfile)):
+                                copyfile(os.path.join(UPLOAD_FOLDER, mpgfile), os.path.join(path, mpgfile))
+                                os.remove(os.path.join(UPLOAD_FOLDER, mpgfile))
+            return path
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    @app.route('/kadmosExportGraph', methods=['POST'])
+    def kadmosExportGraph():
+        """
+           Function exports the current graph to a CMDOWS or kdms file
+
+           :param file: a CMDOWS or kdms file that goes into the user's download folder
+           :return: file
+        """
+        try:
+            # Get request form
+            path = os.path.join(request.form['path'], '')
+            fileName = request.form['fileName']
+            graphID = request.form['graphID']
+            fileType = request.form['fileType']
+            functionOrder = request.form['currentOrder'].split(',')
+
+            graphFileName = TEMP_FILE + '_' + graphID + '.kdms'
+            mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms'
+            if os.path.exists(os.path.join(UPLOAD_FOLDER, mpgFileName)):
+                graph = load(os.path.join(UPLOAD_FOLDER, graphFileName), file_check_critical=False)
+                mpg = load(os.path.join(UPLOAD_FOLDER, mpgFileName), file_check_critical=False)
+            else:
+                graph = load(os.path.join(UPLOAD_FOLDER, graphFileName), file_check_critical=False)
+                mpg = None
+
+            # Add problem function roles if they are not already existing
+            if isinstance(graph, FundamentalProblemGraph):
+                if 'function_order' not in graph.graph['problem_formulation']:
+                    graph.assert_or_add_nested_attribute(['problem_formulation', 'function_order'], None)
+                if 'mdao_architecture' not in graph.graph['problem_formulation']:
+                    graph.assert_or_add_nested_attribute(['problem_formulation', 'mdao_architecture'], 'undefined')
+                if 'allow_unconverged_couplings' not in graph.graph['problem_formulation']:
+                    graph.assert_or_add_nested_attribute(['problem_formulation', 'allow_unconverged_couplings'], False)
+                graph.add_function_problem_roles()
+
+            if not os.path.isdir(path):
+                os.makedirs(os.path.dirname(path))
+
+            if fileType == "kdms":
+                copyfile(os.path.join(UPLOAD_FOLDER, graphFileName), os.path.join(path, fileName + ".kdms"))
+                if os.path.exists(os.path.join(UPLOAD_FOLDER, mpgFileName)):
+                    copyfile(os.path.join(UPLOAD_FOLDER, mpgFileName), os.path.join(path, fileName + '_mpg' + ".kdms"))
+            elif fileType == "cmdows":
+                file = fileName + ".xml"
+                # Save as CMDOWS file
+                graph.save(os.path.join(UPLOAD_FOLDER, fileName), file_type=fileType, graph_check_critical=False,
+                           mpg=mpg)
+                # Copy CMDOWS file from temporary folder to user's download folder
+                copyfile(os.path.join(UPLOAD_FOLDER, file), os.path.join(path, file))
+                # remove temporary CMDOWS file
+                os.remove(os.path.join(UPLOAD_FOLDER, file))
+            else:
+                return ("ERROR: Wrong file type!!!")
+
+            return (path)
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    @app.route('/kadmosSaveGraphTmp', methods=['POST'])
+    def kadmosSaveGraphTmp():
+        """
+           Function saves current graph as new VISTOMS graph and returns it to the VISTOMS package in the browser
+
+           :return: the graph compressed as VISTOMS data
+        """
+        try:
+            # get request form
+            graphID = request.form['graphID']
+            newGraphName = request.form['newGraphName']
+            newGraphID = request.form['newGraphID']
+            function_order = request.form['currentOrder'].split(',')
+
+            tmpDir = UPLOAD_FOLDER
+            graphFileName = TEMP_FILE + '_' + graphID + '.kdms'
+            mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms'
+            if os.path.exists(os.path.join(tmpDir, mpgFileName)):
+                graph = load(os.path.join(tmpDir, graphFileName), file_check_critical=False)
+                mpg = load(os.path.join(tmpDir, mpgFileName), file_check_critical=False)
+            else:
+                graph = load(os.path.join(tmpDir, graphFileName), file_check_critical=False)
+                mpg = None
+
+            newFileName = TEMP_FILE + '_' + newGraphID + '.kdms'
+            graph.graph['name'] = newGraphName
+            graph.save(os.path.join(UPLOAD_FOLDER, newFileName), file_type="kdms", graph_check_critical=False, mpg=mpg)
+
+            newVistomsData = graph.vistoms_add_json(function_order=function_order, mpg=mpg, graph_id=newGraphID)
+
+            return newVistomsData
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    @app.route('/kadmosDeleteGraph', methods=['POST'])
+    def kadmosDeleteGraph():
+        """
+           Function finds all graphs that have been temporarily stored in the temp folder and returns them
+           to the VISTOMS package in the browser. This function is always called when the browser is refreshed by the user.
+
+           :return: the graphs compressed as VISTOMS data
+        """
+        try:
+            # get request form
+            graphID = request.form['graphID']
+
+            tmpDir = UPLOAD_FOLDER
+            graphFileName = TEMP_FILE + '_' + graphID + '.kdms'
+            backupGraphFileName = TEMP_FILE + '_' + graphID + '_backup.kdms'
+            mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms'
+            backupMpgFileName = TEMP_FILE + '_' + graphID + '_mpg_backup.kdms'
+            if os.path.exists(os.path.join(tmpDir, graphFileName)):
+                os.remove(os.path.join(tmpDir, graphFileName))
+            if os.path.exists(os.path.join(tmpDir, backupGraphFileName)):
+                os.remove(os.path.join(tmpDir, backupGraphFileName))
+            if os.path.exists(os.path.join(tmpDir, mpgFileName)):
+                os.remove(os.path.join(tmpDir, mpgFileName))
+            if os.path.exists(os.path.join(tmpDir, backupMpgFileName)):
+                os.remove(os.path.join(tmpDir, backupMpgFileName))
+
+            return kadmosFindTempGraphs()
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    @app.route('/kadmosFindTempGraphs', methods=['POST'])
+    def kadmosFindTempGraphs():
+        """
+           Function finds all graphs that have been temporarily stored in the temp folder and returns them
+           to the VISTOMS package in the browser. This function is always called when the browser is refreshed by the user.
+
+           :return: the graphs compressed as VISTOMS data
+        """
+        try:
+            # First of all, delete all graphs, that end with a _backup
+            deleteBackupGraphs()
+
+            tmpDir = UPLOAD_FOLDER
+            newVIstomsDataArray = []
+            file_list = os.listdir(tmpDir)
+            if file_list:
+                file_list.sort()
+            for file in file_list:
+                if file.endswith(".kdms"):
+                    fileName = file.split('.')[0].split('_')
+                    graphID = fileName[1]
+                    if "mpg" not in fileName:  # Do not loop through mpg files
+                        graphFileName = fileName[0] + "_" + graphID + ".kdms"
+                        mpgFileName = fileName[0] + "_" + graphID + "_mpg.kdms"
+                        if os.path.exists(os.path.join(tmpDir, mpgFileName)):
+                            graph = load(os.path.join(tmpDir, graphFileName), file_check_critical=False)
+                            mpg = load(os.path.join(tmpDir, mpgFileName), file_check_critical=False)
+                        else:
+                            graph = load(os.path.join(tmpDir, graphFileName), file_check_critical=False)
+                            mpg = None
+
+                        # Use function order for VISTOMS if it is available in the graph information
+                        function_order = None
+                        if graph.graph_has_nested_attributes('problem_formulation', 'function_order') and mpg == None:
+                            function_order = graph.graph['problem_formulation']['function_order']
+
+                        graph.save(os.path.join(UPLOAD_FOLDER, graphFileName), file_type="kdms",
+                                   graph_check_critical=False, mpg=mpg)
+
+                        newVIstomsDataArray.append(
+                            graph.vistoms_add_json(graph_id=graphID, function_order=function_order,
+                                                   mpg=mpg))
+
+            return jsonify(newVIstomsDataArray)
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    @app.route('/kadmosRevertLastStep', methods=['POST'])
+    def kadmosRevertLastStep():
+        """
+           Function to revert the last graph manipulation step by returning the _backup file from the tepm folder
+           :return: the graph compressed as VISTOMS data
+        """
+        try:
+            # get request form
+            graphID = request.form['graphID']
+
+            tmpDir = UPLOAD_FOLDER
+            graphFileName = TEMP_FILE + '_' + graphID + '.kdms'
+            mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms'
+            backupGraphFileName = TEMP_FILE + '_' + graphID + '_backup.kdms'
+            backupMpgFileName = TEMP_FILE + '_' + graphID + '_backup_mpg.kdms'
+
+            graph = load(os.path.join(tmpDir, graphFileName), file_check_critical=False)
+            backupGraph = load(os.path.join(tmpDir, backupGraphFileName), file_check_critical=False)
+            if os.path.exists(os.path.join(tmpDir, mpgFileName)):
+                mpg = load(os.path.join(tmpDir, mpgFileName), file_check_critical=False)
+                backupMpg = load(os.path.join(tmpDir, backupMpgFileName), file_check_critical=False)
+            else:
+                mpg = None
+                backupMpg = None
+
+            # Switch graph and backup graph (What used to be the backup graph is now the new graph and vice versa)
+            graph.save(os.path.join(UPLOAD_FOLDER, backupGraphFileName), file_type="kdms", graph_check_critical=False,
+                       mpg=backupMpg)
+            backupGraph.save(os.path.join(UPLOAD_FOLDER, graphFileName), file_type="kdms", graph_check_critical=False,
+                             mpg=mpg)
+
+            # Get function_oder of the backup graph
+            function_order = None
+            if backupGraph.graph_has_nested_attributes('problem_formulation', 'function_order'):
+                function_order = backupGraph.graph['problem_formulation']['function_order']
+
+            newVistomsData = backupGraph.vistoms_add_json(function_order=function_order, mpg=mpg, graph_id=graphID)
+
+            return newVistomsData
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    def savePreviousGraph(graph_id):
+        """
+            Function saves the last graph, so you can revert a graph change within VISTOMS
+
+            :param graph: Initial fundamental problem graph (FPG) to start working on the MDAO architecture definition
+            :return: New VISTOMS json data with initial FPG
+        """
+        path = UPLOAD_FOLDER
+        # current graph and mpg name
+        graphFileName = TEMP_FILE + '_' + graph_id + '.kdms'
+        mpgFileName = TEMP_FILE + '_' + graph_id + '_mpg.kdms'
+
+        # Save graph as backup file
+        backupGraphFileName = TEMP_FILE + '_' + graph_id + '_backup.kdms'
+        copyfile(os.path.join(path, graphFileName), os.path.join(path, backupGraphFileName))
+        if os.path.exists(os.path.join(path, mpgFileName)):
+            # If mpg exists, save it as well
+            backupMpgFileName = TEMP_FILE + '_' + graph_id + '_mpg_backup.kdms'
+            copyfile(os.path.join(path, mpgFileName), os.path.join(path, backupMpgFileName))
+
+    def deleteBackupGraphs():
+        """
+            Function deletes all graphs that end with a _backup
+        """
+        for file in os.listdir(UPLOAD_FOLDER):
+            if file.endswith("_backup.kdms"):
+                os.remove(os.path.join(UPLOAD_FOLDER, file))
+
+    ########################################################################################################################
+
+    # Graph inspection functions
+    ########################################################################################################################
+    @app.route('/kadmosFindAllNodes', methods=['POST'])
+    def kadmosFindAllNodes():
+        """
+            Function to get all nodes from certain categories and return them
+
+            :param method: The method for sorting the nodes. Specified by the user from VISTOMS
+            :return: New VISTOMS json data with updated design competences
+        """
+        try:
+            # Get request form
+            graphID = request.form['graphID']
+            category = str(request.form['category'])
+            sub_category = str(request.form['sub_category'])
+            attr_cond = ast.literal_eval(request.form['attr_cond'])
+            attr_include = ast.literal_eval(request.form['attr_include'])
+            attr_exclude = ast.literal_eval(request.form['attr_exclude'])
+            xPath_include = str(request.form['xPath_include']).split(', ')
+            xPath_exclude = str(request.form['xPath_exclude']).split(', ')
+
+            path = UPLOAD_FOLDER
+            graphFileName = TEMP_FILE + '_' + graphID + '.kdms'
+            mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms'
+            if os.path.exists(os.path.join(path, mpgFileName)):
+                graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+                mpg = load(os.path.join(path, mpgFileName), file_check_critical=False)
+            else:
+                graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+                mpg = None
+
+            if attr_cond == []:
+                attr_cond = None
+            if attr_include == []:
+                attr_include = None
+            if attr_exclude == []:
+                attr_exclude = None
+            if xPath_include == [""]:
+                xPath_include = None
+            if xPath_exclude == [""]:
+                xPath_exclude = None
+
+            allNodes = graph.find_all_nodes(category=category, subcategory=sub_category, attr_cond=attr_cond,
+                                            attr_include=attr_include, attr_exclude=attr_exclude,
+                                            xpath_include=xPath_include, xpath_exclude=xPath_exclude)
+
+            # allNodes_str = ', '.join(str(e) for e in allNodes)
+            allNodes_str = json.dumps(allNodes)
+
+            return allNodes_str
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    @app.route('/kadmosL1Check', methods=['POST'])
+    def kadmosL1Check():
+        """
+            Function to perform category a checks on the graph
+
+            :return: Message, whether the check was successful or not
+        """
+        try:
+            # Get request form
+            graphID = request.form['graphID']
+
+            path = UPLOAD_FOLDER
+            graphFileName = TEMP_FILE + '_' + graphID + '.kdms'
+            mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms'
+            if os.path.exists(os.path.join(path, mpgFileName)):
+                graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+                mpg = load(os.path.join(path, mpgFileName), file_check_critical=False)
+            else:
+                graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+                mpg = None
+
+            check_result = graph._check_category_a()
+
+            if check_result[0] == True:
+                return ("Check successful!")
+            else:
+                return "ERROR: Check was not successful. For further information, please consult the python log"
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    @app.route('/kadmosL2Check', methods=['POST'])
+    def kadmosL2Check():
+        """
+            Function to perform category b checks on the graph
+
+            :return: Message, whether the check was successful or not
+        """
+        try:
+            # Get request form
+            graphID = request.form['graphID']
+
+            path = UPLOAD_FOLDER
+            graphFileName = TEMP_FILE + '_' + graphID + '.kdms'
+            mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms'
+            if os.path.exists(os.path.join(path, mpgFileName)):
+                graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+                mpg = load(os.path.join(path, mpgFileName), file_check_critical=False)
+            else:
+                graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+                mpg = None
+
+            check_result = graph._check_category_b()
+
+            if check_result[0] == True:
+                return ("Check successful!")
+            else:
+                return "ERROR: Check was not successful. For further information, please consult the python log"
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    @app.route('/kadmosL3Check', methods=['POST'])
+    def kadmosL3Check():
+        """
+            Function to perform category c checks on the graph
+
+            :return: Message, whether the check was successful or not
+        """
+        try:
+            # Get request form
+            graphID = request.form['graphID']
+
+            path = UPLOAD_FOLDER
+            graphFileName = TEMP_FILE + '_' + graphID + '.kdms'
+            mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms'
+            if os.path.exists(os.path.join(path, mpgFileName)):
+                graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+                mpg = load(os.path.join(path, mpgFileName), file_check_critical=False)
+            else:
+                graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+                mpg = None
+
+            check_result = graph._check_category_c()
+
+            if check_result[0] == True:
+                return ("Check successful!")
+            else:
+                return "ERROR: Check was not successful. For further information, please consult the python log"
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    ########################################################################################################################
+
+    # FPG manipulation functions
+    ########################################################################################################################
+    @app.route('/kadmosStartDefiningMDOProblem', methods=['POST'])
+    def kadmosStartDefiningMDOProblem():
+        """
+            Function to start an MDO problem
+
+            :param fpg_initial: Initial fundamental problem graph (FPG) to start working on the MDO problem definition
+            :return: New VISTOMS json data with initial FPG
+        """
+        try:
+            # Get request form
+            graphID = request.form['graphID']
+            functionOrder = request.form['currentOrder'].split(',')
+            newGraphID = request.form['newGraphID']
+            newGraphName = request.form['newGraphName']
+
+            newFileName = TEMP_FILE + '_' + newGraphID + '.kdms'
+
+            path = UPLOAD_FOLDER
+            graphFileName = TEMP_FILE + '_' + graphID + '.kdms'
+            mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms'
+            if os.path.exists(os.path.join(path, mpgFileName)):
+                return ("ERROR: Graph is already an MDPG! FPG Cannot be initialized again!")
+            else:
+                mpg = None
+
+                graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+
+                if isinstance(graph, FundamentalProblemGraph):
+                    return ("ERROR: Graph is already an FPG and cannot be initialized again!")
+                fpg_initial = graph.deepcopy_as(FundamentalProblemGraph)
+
+                fpg_initial.graph['name'] = newGraphName
+                fpg_initial.graph['description'] = 'Fundamental problem graph to solve the "' + graph.graph[
+                    'name'] + '".'
+                fpg_initial.graph['problem_formulation'] = dict()
+                fpg_initial.graph['problem_formulation']['function_order'] = functionOrder
+                fpg_initial.graph['problem_formulation']['mdao_architecture'] = "None"
+
+                # Add the graph with the updated function order to VISTOMS
+                newVistomsData = fpg_initial.vistoms_add_json(graph_id=newGraphID, mpg=mpg)
+                # Save the graph in temp/tmp.kdms
+                fpg_initial.save(os.path.join(UPLOAD_FOLDER, newFileName), file_type="kdms", graph_check_critical=False,
+                                 mpg=mpg)
+
+                return newVistomsData
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    @app.route('/kadmosChangeNodePos', methods=['POST'])
+    def kadmosChangeNodePos():
+        """
+            Function to change the position of a node (competence) within the graph
+
+            :param newPos: Initial fundamental problem graph (FPG) to start working on the MDO problem definition
+            :return: New VISTOMS json data with initial FPG
+        """
+        try:
+            # Get request form
+            graphID = request.form['graphID']
+            nodeName = str(request.form['nodeName'])
+            function_order = request.form['currentOrder'].split(',')
+            newPos = int(request.form['newPos'])
+
+            # Save previous graph as backup before making the changes
+            savePreviousGraph(graphID)
+
+            path = UPLOAD_FOLDER
+            graphFileName = TEMP_FILE + '_' + graphID + '.kdms'
+            mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms'
+            if os.path.exists(os.path.join(path, mpgFileName)):
+                return (
+                    "ERROR: You cannot change a competence's position on an existing MPG! Please go back to the FPG or "
+                    "RCG to do so.")
+            else:
+                graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+                mpg = None
+
+                # Change position of a node in th XDSM
+
+                # Get tool list and put the coordinator in the top left corner
+                function_order.remove(nodeName)
+                function_order.insert(newPos, nodeName)
+                if isinstance(graph, FundamentalProblemGraph):
+                    graph.graph['problem_formulation']['function_order'] = function_order
+                    if 'problem_role' in graph.nodes[function_order[0]]:
+                        graph.add_function_problem_roles()
+
+                # Add the graph with the updated function order to VISTOMS
+                newVistomsData = graph.vistoms_add_json(function_order=function_order, graph_id=graphID, mpg=mpg)
+                # Save the graph in temp/tmp.kdms
+                graph.save(os.path.join(UPLOAD_FOLDER, TEMP_FILE + '_' + graphID + '.kdms'), file_type='kdms',
+                           graph_check_critical=False, mpg=mpg)
+                return newVistomsData
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    @app.route('/kadmosDeleteNode', methods=['POST'])
+    def kadmosDeleteNode():
+        """
+            Function deletes a node from the graph and returns the updated graph data to VISTOMS
+            :param nodeName: name of the node to be deleted
+            :return: VISTOMS json data with graph information
+        """
+        try:
+            # Get request form
+            graphID = request.form['graphID']
+            nodeName = str(request.form['nodeName'])
+            function_order = request.form['currentOrder'].split(',')
+
+            # Save previous graph as backup before making the changes
+            savePreviousGraph(graphID)
+
+            path = UPLOAD_FOLDER
+            graphFileName = TEMP_FILE + '_' + graphID + '.kdms'
+            mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms'
+            if os.path.exists(os.path.join(path, mpgFileName)):
+                return (
+                    "ERROR: You cannot remove a competence from an existing MPG! Please go back to the FPG or RCG to "
+                    "do so.")
+            else:
+                graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+                mpg = None
+
+                # remove the node from the graph
+                graph.remove_function_nodes(nodeName)
+                # update function order
+                function_order.remove(nodeName)
+
+                # Add the graph with the updated function order to VISTOMS
+                newVistomsData = graph.vistoms_add_json(function_order=function_order, graph_id=graphID, mpg=mpg)
+                # Save the graph in temp/tmp.kdms
+                graph.save(os.path.join(UPLOAD_FOLDER, TEMP_FILE + '_' + graphID + '.kdms'), file_type='kdms',
+                           graph_check_critical=False, mpg=mpg)
+
+                return newVistomsData
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    @app.route('/kadmosDeleteEdge', methods=['POST'])
+    def kadmosDeleteEdge():
+        """
+            Function deletes an edge from the graph and returns the updated graph data to VISTOMS
+            :param nodeName: name of the node that is the input provider of the edge
+            :param edgeName: name of the edge to be deleted
+            :return: VISTOMS json data with graph information
+        """
+        try:
+            # Get request form
+            graphID = request.form['graphID']
+            nodeName = str(request.form['nodeName'])
+            edgeName = str(request.form['edgeName'])
+            function_order = request.form['currentOrder'].split(',')
+
+            # Save previous graph as backup before making the changes
+            savePreviousGraph(graphID)
+
+            path = UPLOAD_FOLDER
+            graphFileName = TEMP_FILE + '_' + graphID + '.kdms'
+            mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms'
+            if os.path.exists(os.path.join(path, mpgFileName)):
+                graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+                mpg = load(os.path.join(path, mpgFileName), file_check_critical=False)
+            else:
+                graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+                mpg = None
+
+            # remove the edge
+            graph.remove_edge(nodeName, edgeName)
+            # Add the graph with the updated function order to VISTOMS
+            newVistomsData = graph.vistoms_add_json(function_order=function_order, graph_id=graphID, mpg=mpg)
+            # Save the graph in temp/tmp.kdms
+            graph.save(os.path.join(UPLOAD_FOLDER, TEMP_FILE + '_' + graphID + '.kdms'), file_type='kdms',
+                       graph_check_critical=False, mpg=mpg)
+
+            return newVistomsData
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    @app.route('/kadmosExcludeDesignCompetences', methods=['POST'])
+    def kadmosExcludeDesignCompetences():
+        """
+            Function to exclude design competences as requested by the user from VISTOMS
+
+            :param nodeList: List of competences that shall be excluded
+            :return: New VISTOMS json data with excluded design competences deleted
+        """
+        try:
+            # Get request form
+            graphID = request.form['graphID']
+            nodeList = request.form['nodeList'].split(',')
+            function_order = request.form['currentOrder'].split(',')
+
+            # Save previous graph as backup before making the changes
+            savePreviousGraph(graphID)
+
+            path = UPLOAD_FOLDER
+            graphFileName = TEMP_FILE + '_' + graphID + '.kdms'
+            mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms'
+            if os.path.exists(os.path.join(path, mpgFileName)):
+                return (
+                    "ERROR: You cannot remove a competence from an existing MPG! Please go back to the FPG or RCG to "
+                    "do so.")
+            else:
+                graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+                mpg = None
+
+                fpg = FundamentalProblemGraph(graph)
+
+                # Remove a node from the graph
+                for nodeName in nodeList:
+                    fpg.remove_function_nodes(nodeName)
+                    function_order.remove(nodeName)
+                # Assign new function order to problem formulation
+                fpg.graph['problem_formulation']['function_order'] = function_order
+
+                # Add the graph with the updated function order to VISTOMS
+                newVistomsData = fpg.vistoms_add_json(function_order=function_order, graph_id=graphID, mpg=mpg)
+                # Save the graph in temp/tmp.kdms
+                fpg.save(os.path.join(UPLOAD_FOLDER, TEMP_FILE + '_' + graphID + '.kdms'),
+                         file_type='kdms', graph_check_critical=False, mpg=mpg)
+                return newVistomsData
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    @app.route('/kadmosMergeSeqDesignCompetences', methods=['POST'])
+    def kadmosMergeSeqDesignCompetences():
+        """
+            Function to merge design competences that run sequentially as requested by the user from VISTOMS
+
+            :param nodeList: List of competences that shall be merged
+            :return: New VISTOMS json data with merged design competences
+        """
+        try:
+            # Get request form
+            graphID = request.form['graphID']
+            function_order = request.form['currentOrder'].split(',')
+            nodeList = request.form['nodeList'].split(',')
+
+            # Save previous graph as backup before making the changes
+            savePreviousGraph(graphID)
+
+            path = UPLOAD_FOLDER
+            graphFileName = TEMP_FILE + '_' + graphID + '.kdms'
+            mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms'
+            if os.path.exists(os.path.join(path, mpgFileName)):
+                return (
+                    "ERROR: You cannot merge comeptences on an existing MPG! Please go back to the FPG or RCG to do "
+                    "so.")
+            else:
+                graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+                mpg = None
+
+                new_node = '-'.join(nodeList) + '--seq'
+
+                if isinstance(graph, FundamentalProblemGraph):
+                    fpg = graph
+                else:
+                    fpg = FundamentalProblemGraph(graph)
+
+                fpg = fpg.merge_sequential_functions(nodeList, new_label=new_node)
+                # adjust function order
+                function_order = [new_node if func == nodeList[0] else func for func in function_order]
+                for func in nodeList[1:]:
+                    function_order.remove(func)
+                # Add the graph with the updated function order to VISTOMS
+                newVistomsData = fpg.vistoms_add_json(function_order=function_order, graph_id=graphID, mpg=mpg)
+                # Save the graph in temp/tmp.kdms
+                fpg.save(os.path.join(UPLOAD_FOLDER, TEMP_FILE + '_' + graphID + '.kdms'),
+                         file_type='kdms', graph_check_critical=False, mpg=mpg)
+                return newVistomsData
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    @app.route('/kadmosMergeParDesignCompetences', methods=['POST'])
+    def kadmosMergeParDesignCompetences():
+        """
+            Function to merge design competences that run in parallel as requested by the user from VISTOMS
+
+            :param nodeList: List of competences that shall be merged
+            :return: New VISTOMS json data with merged design competences
+        """
+        try:
+            # Get request form
+            graphID = request.form['graphID']
+            function_order = request.form['currentOrder'].split(',')
+            nodeList = request.form['nodeList'].split(',')
+
+            # Save previous graph as backup before making the changes
+            savePreviousGraph(graphID)
+
+            path = UPLOAD_FOLDER
+            graphFileName = TEMP_FILE + '_' + graphID + '.kdms'
+            mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms'
+            if os.path.exists(os.path.join(path, mpgFileName)):
+                return (
+                    "ERROR: You cannot merge comeptences on an existing MPG! Please go back to the FPG or RCG to do "
+                    "so.")
+            else:
+                graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+                mpg = None
+
+                new_node = '-'.join(nodeList) + '--par'
+
+                if isinstance(graph, FundamentalProblemGraph):
+                    fpg = graph
+                else:
+                    fpg = FundamentalProblemGraph(graph)
+
+                fpg = fpg.merge_parallel_functions(nodeList, new_label=new_node)
+                # adjust function order
+                function_order = [new_node if func == nodeList[0] else func for func in function_order]
+                for func in nodeList[1:]:
+                    function_order.remove(func)
+
+                # Add the graph with the updated function order to VISTOMS
+                newVistomsData = fpg.vistoms_add_json(function_order=function_order, graph_id=graphID, mpg=mpg)
+                # Save the graph in temp/tmp.kdms
+                fpg.save(os.path.join(UPLOAD_FOLDER, TEMP_FILE + '_' + graphID + '.kdms'),
+                         file_type='kdms', graph_check_critical=False, mpg=mpg)
+                return newVistomsData
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    @app.route('/kadmosMergeFuncModDesignCompetences', methods=['POST'])
+    def kadmosMergeFuncModDesignCompetences():
+        """
+            Function to merge design competences that run in different modes as requested by the user from VISTOMS
+
+            :param nodeList: List of competences that shall be merged
+            :return: New VISTOMS json data with merged design competences
+        """
+        try:
+            # Get request form
+            graphID = request.form['graphID']
+            function_order = request.form['currentOrder'].split(',')
+            nodeList = request.form['nodeList'].split(',')
+
+            # Save previous graph as backup before making the changes
+            savePreviousGraph(graphID)
+
+            path = UPLOAD_FOLDER
+            graphFileName = TEMP_FILE + '_' + graphID + '.kdms'
+            mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms'
+            if os.path.exists(os.path.join(path, mpgFileName)):
+                return (
+                    "ERROR: You cannot merge comeptences on an existing MPG! Please go back to the FPG or RCG to do "
+                    "so.")
+            else:
+                graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+                mpg = None
+
+                if isinstance(graph, FundamentalProblemGraph):
+                    fpg = graph
+                else:
+                    fpg = FundamentalProblemGraph(graph)
+
+                base_function = fpg.node[nodeList[0]]['name']
+                modes = [str(string[string.find('[') + 1:string.find(']')]) for string in nodeList]
+                suffices = [str(string[string.find('_'):string.find('[')]) for string in nodeList]
+                new_node = base_function + '-merged[' + str(len(nodeList)) + 'modes]'
+
+                fpg = fpg.merge_function_modes(base_function, modes, new_label=new_node, version='1.0', instance=1,
+                                               suffices=suffices)
+                # adjust function order
+                function_order = [new_node if func == nodeList[0] else func for func in function_order]
+                for func in nodeList[1:]:
+                    function_order.remove(func)
+
+                # Add the graph with the updated function order to VISTOMS
+                newVistomsData = fpg.vistoms_add_json(function_order=function_order, graph_id=graphID, mpg=mpg)
+                # Save the graph in temp/tmp.kdms
+                fpg.save(os.path.join(UPLOAD_FOLDER, TEMP_FILE + '_' + graphID + '.kdms'),
+                         file_type='kdms', graph_check_critical=False, mpg=mpg)
+                return newVistomsData
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    @app.route('/kadmosRemoveCollision', methods=['POST'])
+    def kadmosRemoveCollision():
+        """
+            Function to remove collisions coming from specific design competences as requested by the user from VISTOMS
+
+            :param nodeList: List of competences for which collisions should be removed
+            :return: New VISTOMS json data with updated design competences
+        """
+        try:
+            # Get request form
+            graphID = request.form['graphID']
+            nodeList = request.form['nodeList'].split(',')
+            function_order = request.form['currentorder'].split(',')
+
+            # Save previous graph as backup before making the changes
+            savePreviousGraph(graphID)
+
+            path = UPLOAD_FOLDER
+            graphFileName = TEMP_FILE + '_' + graphID + '.kdms'
+            mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms'
+            if os.path.exists(os.path.join(path, mpgFileName)):
+                return (
+                    "ERROR: You cannot merge comeptences on an existing MPG! Please go back to the FPG or RCG to do "
+                    "so.")
+            else:
+                graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+                mpg = None
+
+                if isinstance(graph, FundamentalProblemGraph):
+                    fpg = graph
+                else:
+                    fpg = FundamentalProblemGraph(graph)
+
+                for collision_source in nodeList:
+                    fpg.disconnect_problematic_variables_from(collision_source)
+
+                    fpg.graph['problem_formulation']['function_order'] = function_order
+
+                # Add the graph with the updated function order to VISTOMS
+                newVistomsData = fpg.vistoms_add_json(function_order=function_order, graph_id=graphID, mpg=mpg)
+                # Save the graph in temp/tmp.kdms
+                fpg.save(os.path.join(UPLOAD_FOLDER, TEMP_FILE + '_' + graphID + '.kdms'),
+                         file_type='kdms', graph_check_critical=False, mpg=mpg)
+                return newVistomsData
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    @app.route('/kadmosGetPossibleFunctionOrder', methods=['POST'])
+    def kadmosGetPossibleFunctionOrder():
+        """
+            Function to get a possible function order
+
+            :param method: The method for sorting the nodes. Specified by the user from VISTOMS
+            :return: New VISTOMS json data with updated design competences
+        """
+        try:
+            # Get request form
+            graphID = request.form['graphID']
+            method = request.form['sortingMethod']
+
+            # Save previous graph as backup before making the changes
+            savePreviousGraph(graphID)
+
+            path = UPLOAD_FOLDER
+            graphFileName = TEMP_FILE + '_' + graphID + '.kdms'
+            mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms'
+            if os.path.exists(os.path.join(path, mpgFileName)):
+                return (
+                    "ERROR: You cannot merge comeptences on an existing MPG! Please go back to the FPG or RCG to do "
+                    "so.")
+            else:
+                graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+                mpg = None
+
+                if isinstance(graph, FundamentalProblemGraph):
+                    fpg = graph
+                else:
+                    fpg = FundamentalProblemGraph(graph)
+
+                # Getting the possible function order with the method specified by the user
+                function_order = fpg.get_possible_function_order(method)
+                fpg.assert_or_add_nested_attribute(['problem_formulation', 'mdao_architecture'], 'undefined')
+                fpg.graph['problem_formulation']['function_order'] = function_order
+                if 'problem_role' in fpg.nodes[function_order[0]]:
+                    fpg.add_function_problem_roles()
+
+                # Save the graph in temp/tmp.kdms
+                fpg.save(os.path.join(UPLOAD_FOLDER, TEMP_FILE + '_' + graphID + '.kdms'),
+                         file_type='kdms', graph_check_critical=False, mpg=mpg)
+
+                # Add the graph with the updated function order to VISTOMS
+                newVistomsData = fpg.vistoms_add_json(function_order=function_order, graph_id=graphID, mpg=mpg)
+
+                return newVistomsData
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    @app.route('/kadmosMakeAllVariablesValid', methods=['POST'])
+    def kadmosMakeAllVariablesValid():
+        """
+            Function to make all variables from the graph valid --> Eliminates colissions
+
+            :return: New VISTOMS json data with updated design competences
+        """
+        try:
+            # get request form
+            graphID = request.form['graphID']
+            function_order = request.form['currentOrder'].split(',')
+
+            # Save previous graph as backup before making the changes
+            savePreviousGraph(graphID)
+
+            path = UPLOAD_FOLDER
+            graphFileName = TEMP_FILE + '_' + graphID + '.kdms'
+            mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms'
+            if os.path.exists(os.path.join(path, mpgFileName)):
+                return ("ERROR: You cannot do that on an existing MPG! Please go back to the FPG or RCG to do so.")
+            else:
+                graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+                mpg = None
+
+                if isinstance(graph, FundamentalProblemGraph):
+                    fpg = graph
+                else:
+                    fpg = FundamentalProblemGraph(graph)
+
+                fpg.graph['problem_formulation']['function_order'] = function_order
+
+                # Function to check the graph for collisions and holes. Collisions are solved based on the function order
+                # and holes will simply be removed.
+                fpg.make_all_variables_valid()
+
+                # Add the graph with the updated function order to VISTOMS
+                newVistomsData = fpg.vistoms_add_json(function_order=function_order, graph_id=graphID, mpg=mpg)
+                # Save the graph in temp/tmp.kdms
+                fpg.save(os.path.join(UPLOAD_FOLDER, TEMP_FILE + '_' + graphID + '.kdms'),
+                         file_type='kdms', graph_check_critical=False, mpg=mpg)
+                return newVistomsData
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    @app.route('/kadmosAddProblemFunctionRoles', methods=['POST'])
+    def kadmosAddProblemFunctionRoles():
+        """
+            Function to Add the problem function roles to the graph
+
+            :return: New VISTOMS json data with updated design competences
+        """
+        try:
+            # get request form
+            graphID = request.form['graphID']
+            function_order = request.form['currentOrder'].split(',')
+
+            # Save previous graph as backup before making the changes
+            savePreviousGraph(graphID)
+
+            path = UPLOAD_FOLDER
+            graphFileName = TEMP_FILE + '_' + graphID + '.kdms'
+            mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms'
+            if os.path.exists(os.path.join(path, mpgFileName)):
+                return ("ERROR: You cannot do that on an existing MPG! Please go back to the FPG or RCG to do so.")
+            else:
+                graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+                mpg = None
+
+                if isinstance(graph, FundamentalProblemGraph):
+                    fpg = graph
+                else:
+                    fpg = FundamentalProblemGraph(graph)
+
+                fpg.graph['problem_formulation']['function_order'] = function_order
+
+                # Add the function problem roles (pre-coupling, coupled, post-coupling)
+                fpg.add_function_problem_roles()
+
+                # Add the graph with the updated function order to VISTOMS
+                newVistomsData = fpg.vistoms_add_json(function_order=function_order, graph_id=graphID, mpg=mpg)
+                # Save the graph in temp/tmp.kdms
+                fpg.save(os.path.join(UPLOAD_FOLDER, TEMP_FILE + '_' + graphID + '.kdms'),
+                         file_type='kdms', graph_check_critical=False, mpg=mpg)
+                return newVistomsData
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    @app.route('/kadmosMarkVariable', methods=['POST'])
+    def kadmosMarkVariable():
+        """
+            Function to mark a variable as "special variable" (constraint, objective, design variable, quantity of interest)
+            :param xPath: xPath of the variable in the XML schema
+            :param variableType: type of the variable it shall be marked as (constraint, objective, design variable,
+                quantity of interest)
+            :return: VISTOMS json data with graph information
+        """
+        try:
+            # get request form
+            graphID = request.form['graphID']
+            function_order = request.form['currentOrder'].split(',')
+            variableType = request.form['variableType']
+            xPath = request.form['xPath']
+            operator = request.form['operator']
+            upperBound = float(request.form['upperBound'])
+            lowerBound = float(request.form['lowerBound'])
+            nominalValue = float(request.form['nominalValue'])
+
+            # Save previous graph as backup before making the changes
+            savePreviousGraph(graphID)
+
+            path = UPLOAD_FOLDER
+            graphFileName = TEMP_FILE + '_' + graphID + '.kdms'
+            mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms'
+            if os.path.exists(os.path.join(path, mpgFileName)):
+                return ('ERROR: This function can only be performed on an FPG!')
+            else:
+                graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+                mpg = None
+
+            if isinstance(graph, FundamentalProblemGraph):
+                fpg = graph
+            else:
+                fpg = FundamentalProblemGraph(graph)
+
+            if (variableType == 'designVariable'):
+                fpg.mark_as_design_variable(xPath, nominal_value=nominalValue, upper_bound=upperBound,
+                                            lower_bound=lowerBound)
+            elif (variableType == 'objective'):
+                fpg.mark_as_objective(xPath)
+            elif (variableType == 'constraint'):
+                fpg.mark_as_constraint(xPath, reference_value=nominalValue, operator=operator)
+            elif (variableType == 'quantityOfInterest'):
+                fpg.mark_as_qois([xPath])
+            else:
+                return ("ERROR: Something went wrong in KADMOS!")
+
+            # Add the graph with the updated function order to VISTOMS
+            newVistomsData = fpg.vistoms_add_json(function_order=function_order, graph_id=graphID, mpg=mpg)
+            # Save the graph in temp/tmp.kdms
+            fpg.save(os.path.join(UPLOAD_FOLDER, TEMP_FILE + '_' + graphID + '.kdms'), file_type='kdms',
+                     graph_check_critical=False, mpg=mpg)
+
+            return newVistomsData
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    @app.route('/kadmosUnmarkVariable', methods=['POST'])
+    def kadmosUnmarkVariable():
+        """
+            Function to unmark a previously marked variable
+            :param xPath: xPath of the variable in the XML schema
+            :return: VISTOMS json data with graph information
+        """
+        try:
+            # get request form
+            graphID = request.form['graphID']
+            function_order = request.form['currentOrder'].split(',')
+            xPath = request.form['xPath']
+
+            # Save previous graph as backup before making the changes
+            savePreviousGraph(graphID)
+
+            path = UPLOAD_FOLDER
+            graphFileName = TEMP_FILE + '_' + graphID + '.kdms'
+            mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms'
+            if os.path.exists(os.path.join(path, mpgFileName)):
+                return ('ERROR: This function can only be performed on an FPG!')
+            else:
+                graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+                mpg = None
+
+            if isinstance(graph, FundamentalProblemGraph):
+                fpg = graph
+            else:
+                fpg = FundamentalProblemGraph(graph)
+
+            fpg.unmark_variable(xPath)
+
+            # Add the graph with the updated function order to VISTOMS
+            newVistomsData = fpg.vistoms_add_json(function_order=function_order, graph_id=graphID, mpg=mpg)
+            # Save the graph in temp/tmp.kdms
+            fpg.save(os.path.join(UPLOAD_FOLDER, TEMP_FILE + '_' + graphID + '.kdms'), file_type='kdms',
+                     graph_check_critical=False, mpg=mpg)
+
+            return newVistomsData
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    @app.route('/kadmosRemoveUnusedOutputs', methods=['POST'])
+    def kadmosRemoveUnusedOutputs():
+        """
+            Function to remove all unused variables that are output to the coordinator
+
+            :return: New VISTOMS json data with updated design competences
+        """
+        try:
+            # get request form
+            graphID = request.form['graphID']
+            function_order = request.form['currentOrder'].split(',')
+            cleanUp_str = request.form['cleanUp']
+            if cleanUp_str == 'True':
+                cleanUp = True
+            else:
+                cleanUp = False
+
+            # Save previous graph as backup before making the changes
+            savePreviousGraph(graphID)
+
+            path = UPLOAD_FOLDER
+            graphFileName = TEMP_FILE + '_' + graphID + '.kdms'
+            mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms'
+            if os.path.exists(os.path.join(path, mpgFileName)):
+                return ("ERROR: You cannot do that on an existing MPG! Please go back to the FPG or RCG to do so.")
+            else:
+                graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+                mpg = None
+
+                if isinstance(graph, FundamentalProblemGraph):
+                    fpg = graph
+                else:
+                    fpg = FundamentalProblemGraph(graph)
+
+                fpg.graph['problem_formulation']['function_order'] = function_order
+
+                # Cleaning of the graph needs to be done in a while loop, to entirely remove all unused elements
+                another_run = True
+                while another_run:
+                    another_run = False
+                    # Delete unused variables
+                    output_nodes = fpg.find_all_nodes(subcategory='all outputs')
+                    for output_node in output_nodes:
+                        if 'problem_role' not in fpg.node[output_node]:
+                            fpg.remove_node(output_node)
+                            another_run = True
+                    # Delete unnecessary functions automatically if the user wants to
+                    if cleanUp:
+                        function_nodes = fpg.find_all_nodes(category='function')
+                        for function_node in function_nodes:
+                            if not fpg.out_edges(function_node):
+                                fpg.remove_function_nodes(function_node)
+                                function_order.remove(function_node)
+                                another_run = True
+
+                # Add the function problem roles (pre-coupling, coupled, post-coupling)
+                fpg.add_function_problem_roles()
+
+                # Add the graph with the updated function order to VISTOMS
+                newVistomsData = fpg.vistoms_add_json(function_order=function_order, graph_id=graphID, mpg=mpg)
+                # Save the graph in temp/tmp.kdms
+                fpg.save(os.path.join(UPLOAD_FOLDER, TEMP_FILE + '_' + graphID + '.kdms'),
+                         file_type='kdms', graph_check_critical=False, mpg=mpg)
+                return newVistomsData
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    ########################################################################################################################
+
+    # MDPG manipulation functions
+    ########################################################################################################################
+    @app.route('/kadmosStartDefiningMDAOArchitecture', methods=['POST'])
+    def kadmosStartDefiningMDAOArchitecture():
+        """
+            Function to start an MDO problem definition
+
+            :param graph: Initial fundamental problem graph (FPG) to start working on the MDAO architecture definition
+            :return: New VISTOMS json data with initial FPG
+        """
+        try:
+            # Get request form
+            graphID = request.form['graphID']
+            functionOrder = request.form['currentOrder'].split(',')
+            newGraphID = request.form['newGraphID']
+            newGraphName = request.form['newGraphName']
+
+            # Save previous graph as backup before making the changes
+            savePreviousGraph(graphID)
+
+            newFileName = TEMP_FILE + '_' + newGraphID + '.kdms'
+
+            path = UPLOAD_FOLDER
+            graphFileName = TEMP_FILE + '_' + graphID + '.kdms'
+            mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms'
+            if os.path.exists(os.path.join(path, mpgFileName)):
+                return ("ERROR: Graph is already an MDPG! FPG Cannot be initialized again!")
+            else:
+                mpg = None
+
+                graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+
+                if not isinstance(graph, FundamentalProblemGraph):
+                    return ("ERROR: Graph is not an FPG yet. Please perform the FPG Manipulation steps first!")
+
+                # check if fpg is well defined
+                check_result = graph._check_category_a()
+                if check_result[0] != True:
+                    return (
+                        "ERROR: The FPG is not well defined yet. Please perform FPG manipulation steps first and check "
+                        "the graph again!")
+
+                mdg = deepcopy(graph)
+                mdg.graph['name'] = newGraphName
+                mdg.graph['description'] = 'MDAO data and process graph to solve the "' + graph.graph['name'] + '".'
+                mdg.graph['problem_formulation'] = dict()
+                mdg.graph['problem_formulation']['function_order'] = functionOrder
+                mdg.graph['problem_formulation']['mdao_architecture'] = "None"
+
+                # Add the graph with the updated function order to VISTOMS
+                newVistomsData = mdg.vistoms_add_json(function_order=functionOrder, graph_id=newGraphID, mpg=mpg)
+                # Save the graph in temp/tmp.kdms
+                mdg.save(os.path.join(UPLOAD_FOLDER, newFileName), file_type="kdms", graph_check_critical=False,
+                         mpg=mpg)
+
+                return newVistomsData
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    @app.route('/kadmosImposeMDAOArchitecture', methods=['POST'])
+    def kadmosImposeMDAOArchitecture():
+        """
+            Function to wrap an MDAO architecture around the MDAO problem
+
+            :param allowUnconvergedCouplings: Bool variable whether unconverged couplings are allowed or not
+            :return: New VISTOMS json data with updated MDAO data and process graphs
+        """
+        try:
+            # Get request form
+            graphID = request.form['graphID']
+            function_order = request.form['currentOrder'].split(',')
+            mdao_architecture = request.form['mdao_architecture']
+            doe_method = request.form['doe_method']
+            coupling_decomposition = request.form['coupling_decomposition']
+            allow_unconverged_couplings_str = request.form['allow_unconverged_couplings']
+            if allow_unconverged_couplings_str == 'True':
+                allow_unconverged_couplings = True
+            else:
+                allow_unconverged_couplings = False
+
+            # Save previous graph as backup before making the changes
+            savePreviousGraph(graphID)
+
+            path = UPLOAD_FOLDER
+            graphFileName = TEMP_FILE + '_' + graphID + '.kdms'
+            mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms'
+            if os.path.exists(os.path.join(path, mpgFileName)):
+                return ("ERROR: You cannot perform this on an existing MPG! Please go back to the FPG to do so.")
+            else:
+                graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+                mpg = None
+
+                mdao_definition = mdao_architecture
+                if coupling_decomposition == 'Gauss-Seidel':
+                    mdao_definition += '-GS'
+                elif coupling_decomposition == 'Jacobi':
+                    mdao_definition += '-J'
+                elif coupling_decomposition == '-':
+                    coupling_decomposition = None
+
+                if not isinstance(graph, FundamentalProblemGraph):
+                    return "ERROR: Your graph is not an FPG yet. Please perform FPG manipulation steps before imposing an" \
+                           " MDAO architecture!"
+
+                fpg = graph
+
+                mdao_definition = mdao_architecture
+                if coupling_decomposition == 'Gauss-Seidel':
+                    mdao_definition += '-GS'
+                elif coupling_decomposition == 'Jacobi':
+                    mdao_definition += '-J'
+                elif coupling_decomposition == '-':
+                    coupling_decomposition = None
+
+                # Define settings of the problem formulation
+                fpg.graph['problem_formulation'] = dict()
+                fpg.graph['problem_formulation']['function_order'] = function_order
+                fpg.graph['problem_formulation']['mdao_architecture'] = mdao_architecture
+                fpg.graph['problem_formulation']['convergence_type'] = coupling_decomposition
+                fpg.graph['problem_formulation']['allow_unconverged_couplings'] = allow_unconverged_couplings
+
+                if mdao_architecture in ['converged-DOE', 'unconverged-DOE']:
+                    if doe_method not in fpg.OPTIONS_DOE_METHODS:
+                        return "ERROR: Invalid DOE method selected, please select a DOE method from the dropdown list"
+
+                    fpg.graph['problem_formulation']['doe_settings'] = {'doe_method': doe_method}
+                    if fpg.graph['problem_formulation']['doe_settings']['doe_method'] in ['Latin hypercube design',
+                                                                                          'Monte Carlo design']:
+                        fpg.graph['problem_formulation']['doe_settings']['doe_seed'] = 6
+                        fpg.graph['problem_formulation']['doe_settings']['doe_runs'] = 5
+                    elif fpg.graph['problem_formulation']['doe_settings']['doe_method'] in ['Full factorial design']:
+                        fpg.graph['problem_formulation']['doe_settings']['doe_runs'] = 5
+
+                fpg.add_function_problem_roles()
+
+                mdg, mpg = fpg.impose_mdao_architecture()
+
+                mpg.graph['name'] = 'XDSM - {}'.format(mdao_definition)
+                mpg.graph['description'] = 'Solution strategy to solve the super-sonic business jet test case ' \
+                                           'optimization problem using the strategy: {}.'.format(mdao_definition)
+                # Add the graph with the updated function order to VISTOMS
+                newVistomsData = mdg.vistoms_add_json(graph_id=graphID, mpg=mpg)
+                # Save the graph in temp/tmp.kdms
+                mdg.save(os.path.join(UPLOAD_FOLDER, TEMP_FILE + '_' + graphID + '.kdms'),
+                         file_type='kdms', graph_check_critical=False, mpg=mpg)
+                return newVistomsData
+
+        except Exception as e:
+            return "ERROR: " + e.message
+            # Logs the error appropriately.
+
+    ########################################################################################################################
+
     # Return the interface
     return app