From 5a2ae084b4416432a2ba83d0323d1897662cf8e3 Mon Sep 17 00:00:00 2001 From: baigner <benedikt.aigner@rwth-aachen.de> Date: Tue, 13 Nov 2018 18:02:21 +0100 Subject: [PATCH] Fixed some bugs and included some new features on setting an mdao architecture. CAUTION: Bliss200 and CO do not work yet! Former-commit-id: 6fafa11c202ccca6418f6692fc58fdbd9b794740 --- kadmos/vistoms/templates/VISTOMS.html | 357 ++++++++++++++++++-------- kadmos/vistoms/templates/info.html | 2 +- kadmos/vistoms/vistoms.py | 73 +++--- 3 files changed, 291 insertions(+), 141 deletions(-) diff --git a/kadmos/vistoms/templates/VISTOMS.html b/kadmos/vistoms/templates/VISTOMS.html index f9b934807..db076ab0a 100644 --- a/kadmos/vistoms/templates/VISTOMS.html +++ b/kadmos/vistoms/templates/VISTOMS.html @@ -592,11 +592,8 @@ closeButton: false, title: "Please select the visualization type", inputType: 'select', + value: 'xdsm', inputOptions: [ - { - text: 'Please choose...', - value: '', - }, { text: 'XDSM view', value: 'xdsm', @@ -19184,20 +19181,26 @@ theVariableData.upperBound = 0.; theVariableData.lowerBound = 0.; theVariableData.nominalValue = 0.; + theVariableData.samples = ""; bootbox.hideAll(); bootbox.confirm({ closeButton: false, title: 'Marking variable as ' + theVariableData.variableType, message:"<form id='infos' action=''>" - +"\Nominal Value: <input type='text' id='nominalValue' name='nominalValue' /><br/>" - +"\Upper Bound: <input type='text' id='upperBound' name='upperBound' /><br/>" - +"\Lower Bound: <input type='text' id='lowerBound' name='lowerBound' />\</form>", + +"\Nominal Value: <input type='number' id='nominalValue' name='nominalValue' value='0' /><br/>" + +"\Upper Bound: <input type='number' id='upperBound' name='upperBound' value='0' /><br/>" + +"\Lower Bound: <input type='number' id='lowerBound' name='lowerBound' value='0' />\</form>" + +"\Sample list (optional): <input type='text' id='samples' name='samples' />\</form>", callback: function(result){ if(result){ theVariableData.nominalValue = parseFloat($('#nominalValue').submit()[0].value.replace(/,/g, '')); theVariableData.upperBound = parseFloat($('#upperBound').submit()[0].value.replace(/,/g, '')); theVariableData.lowerBound = parseFloat($('#lowerBound').submit()[0].value.replace(/,/g, '')); + theVariableData.lowerBound = parseFloat($('#lowerBound').submit()[0].value.replace(/,/g, '')); + theVariableData.samples = $('#samples').submit()[0].value; + + if (isNaN(parseInt(theVariableData.nominalValue)) || isNaN(parseInt(theVariableData.lowerBound)) @@ -20055,7 +20058,14 @@ {text:'Collaborative Optimization',value:'CO'}, {text:'BLISS-2000',value:'BLISS-2000'}] var coupling_decompositions = ['-','Gauss-Seidel','Jacobi'] - var DOE_methods = ['-','Full factorial design','Latin hypercube design','Monte Carlo Design'] + var DOE_methods = ['-', + 'Full factorial design', + 'Latin hypercube design', + 'Monte Carlo design', + 'Custom design table', + 'Uniform design', + 'Box-Behnken design'] + var DOE_settings = [] //################################################################################################// @@ -21588,8 +21598,8 @@ +" </li>" +" <li><a href='#'>Assign...<span>▸</span></a>" +" <ul class='assign'>" - +" <li class='assign_probFunc_roles'><a href='#'>problem function roles</a></li>" +" <li class='assign_parameter_roles'><a href='#'>parameter roles</a></li>" + +" <li class='assign_probFunc_roles'><a href='#'>problem function roles</a></li>" +" </ul>" +" </li>" +" </ul>" @@ -21601,7 +21611,6 @@ +" <ul class='set'>" +" <li class='set_MDAO_architecture'><a href='#'>MDAO architecture</a></li>" +" <li class='set_coupling_decomposition'><a href='#'>Coupling decomposition</a></li>" - +" <li class='set_DOE_method'><a href='#'>DOE method</a></li>" +" </ul>" +" </li>" +" <li class='impose_MDAO_architecture'><a href='#'>Impose MDAO architecture</a></li>" @@ -22941,6 +22950,7 @@ var MDAO_architecture = '-'; var coupling_decomposition = '-'; var DOE_method = '-'; + var allow_unconverged_couplings = 'True'; var set_MDAO_architecture_DOM = d3.select(".set_MDAO_architecture") set_MDAO_architecture_DOM.on("mousedown", function() { @@ -22950,11 +22960,167 @@ bootbox.prompt( { closeButton: false, - title: "Set MDAO Architecture", + title: "<p><b>Set MDAO Architecture</b></p><br>" + +"<p>You can specify the settings for your MDO architecture here.</p>" + +"<p>To actually impose the architecture on your graph, you need to press the button <b>\"Impose MDAO architecture\"</b> afterwards.", inputType: 'select', value: MDAO_architecture, + size: "large", inputOptions: theOptions, - callback: function (result) {if (result){MDAO_architecture = result;}} + callback: function (result) { + if (result) + { + MDAO_architecture = result; + if (!MDAO_architecture.includes("unconverged")) + { + var theOptions = [{text:"yes",value:"True"},{text:"no",value:"False"}] + bootbox.hideAll(); + bootbox.prompt( + { + closeButton: false, + title: "Allow Unconverged Couplings?", + value: "True", + inputType: 'select', + inputOptions: theOptions, + callback: function (result) + { + if (result) + { + allow_unconverged_couplings = result; + } + } + }) + } + if (MDAO_architecture.includes("DOE")) + { + var theOptions = [] + for (var i = 0; i<DOE_methods.length; i++){theOptions.push({text:DOE_methods[i], value:DOE_methods[i]})} + bootbox.prompt( + { + closeButton: false, + title: "Select DOE Method", + value: DOE_method, + inputType: 'select', + inputOptions: theOptions, + callback: function (result) + { + if (result) + { + DOE_method = result; + + + function form_control(text, type, id, form_group) + { + form_group.append("label").text(text) + var input = form_group.append("input") + .attr("id",id) + .attr("class","form-control") + .attr("type",type) + .attr("name",text) + } + function set_doe_settings(ids) + { + var modal = bootbox.dialog( + { + closeButton: false, + message: $(".form-content").html(), + title: "DOE settings", + size: "large", + buttons: [ + { + label: "OK", + className: "btn btn-primary pull-right", + callback: function() { + ids.forEach(function(id) + { + DOE_settings.push({'name': id, 'value': $('form #' + id.split('/').join('_')).val()}) + }) + d3.selectAll(".form-content").remove(); + } + }, + { + label: "Cancel", + className: "btn btn-default pull-right", + callback: function() { + d3.selectAll(".form-content").remove(); + bootbox.hideAll(); + } + } + ] + }); + } + + var html = d3.select("html") + var form_content = html.append("div").attr("class","form-content").attr("style","display:none") + var form = form_content.append("form").attr("class","form").attr("role","form") + var form_group = form.append("div").attr("class","form-group") + if (DOE_method=='Full factorial design') + { + bootbox.hideAll(); + form_control("Number of levels", "number", "levels", form_group) + form_control("Number of runs", "number", "runs", form_group) + set_doe_settings(["levels","runs"]); + } + else if (DOE_method=='Latin hypercube design') + { + bootbox.hideAll(); + form_control("Seed", "number", "seed", form_group) + form_control("Number of runs", "number", "runs", form_group) + set_doe_settings(["seed","runs"]); + } + else if (DOE_method=='Monte Carlo design') + { + bootbox.hideAll(); + form_control("Seed", "number", "seed", form_group) + form_control("Number of runs", "number", "runs", form_group) + set_doe_settings(["seed","runs"]); + } + else if (DOE_method=='Box-Behnken design') + { + bootbox.hideAll(); + form_control("Number of center runs", "number", "center_runs", form_group) + set_doe_settings(["center_runs"]); + } + else if (DOE_method=='Uniform design') + { + bootbox.hideAll(); + form_control("Seed", "number", "seed", form_group) + form_control("Number of runs", "number", "runs", form_group) + set_doe_settings(["seed","runs"]); + } + else if (DOE_method=='Custom design table') + { + } + else; + + } + else + { + bootbox.hideAll(); + } + } + }) + } + if (MDAO_architecture == "converged-MDA" + || MDAO_architecture == "MDF" + || MDAO_architecture == "converged-DOE") + { + var theOptions = [] + for (var i = 0; i<coupling_decompositions.length; i++){theOptions.push({text:coupling_decompositions[i], value:coupling_decompositions[i]})} + bootbox.prompt( + { + closeButton: false, + title: "Select Coupling Decomposition", + value: coupling_decomposition, + inputType: 'select', + inputOptions: theOptions, + callback: function (result) { + if (result){coupling_decomposition = result;} + else {bootbox.hideAll()} + } + }) + } + }} }) }) @@ -22971,96 +23137,84 @@ value: coupling_decomposition, inputType: 'select', inputOptions: theOptions, - callback: function (result) {if (result){coupling_decomposition = result;}} - }) - }) - - var set_DOE_method_DOM = d3.select(".set_DOE_method") - set_DOE_method_DOM.on("mousedown", function() - { - var theOptions = [] - for (var i = 0; i<DOE_methods.length; i++){theOptions.push({text:DOE_methods[i], value:DOE_methods[i]})} - bootbox.hideAll(); - bootbox.prompt( + callback: function (result) { - closeButton: false, - title: "Select DOE Method", - value: DOE_method, - inputType: 'select', - inputOptions: theOptions, - callback: function (result) {if (result){DOE_method = result;}} - }) - }) + if (result) + { + coupling_decomposition = result; + var theOptions = [{text:"yes",value:"True"},{text:"no",value:"False"}] + bootbox.hideAll(); + bootbox.prompt( + { + closeButton: false, + title: "Allow Unconverged Couplings?", + value: "True", + inputType: 'select', + inputOptions: theOptions, + callback: function (result) + { + if (result) + { + allow_unconverged_couplings = result; + } + } + }) + } + } + }) + }) var impose_MDAO_architecture_DOM = d3.select(".impose_MDAO_architecture") impose_MDAO_architecture_DOM.on("mousedown", function() - { - var theOptions = [{text:"yes",value:"True"},{text:"no",value:"False"}] - bootbox.hideAll(); - bootbox.prompt( - { - closeButton: false, - title: "Allow Unconverged Couplings?", - value: "True", - inputType: 'select', - inputOptions: theOptions, - callback: function (result) - { - if (result) - { - var allow_unconverged_couplings = result; - var bootboxContent = {title: "Impose MDAO Architecture", message: '<p>Please be patient...</p>'}; - var xhr = $.ajax( - { - type: 'POST', - url: '/kadmos_impose_MDAO_architecture', - data: {'graphID':graphID, - 'currentOrder':nodeOrder, - 'mdao_architecture':MDAO_architecture, - 'doe_method':DOE_method, - 'coupling_decomposition':coupling_decomposition, - 'allow_unconverged_couplings':allow_unconverged_couplings, - 'sessionId':sessionId}, - success: function(result) - { - if (result.includes("ERROR:")) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - else - { - var updatedData = {}; - updatedData = data; - var graphData = JSON.parse(result); - for (var i = 0; i < updatedData.graphs.length; i++) - { - if (graphID == updatedData.graphs[i].id) - { - updatedData.graphs[i] = graphData.graphs[0]; - } - } - - clearView(); - makeKadmosMenu(updatedData); - xdsm_script(updatedData,graphID); - - bootboxContent.message = "Success!" - kadmosSuccessMessage(bootboxContent) - } - }, - error: function(result) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - }); - kadmosHavePatience(xhr, bootboxContent) - - } - - } - }) + { + var bootboxContent = {title: "Impose MDAO Architecture", message: '<p>Please be patient...</p>'}; + DOE_settings.push({'name': 'method','value':DOE_method}) + var xhr = $.ajax( + { + type: 'POST', + url: '/kadmos_impose_MDAO_architecture', + data: {'graphID':graphID, + 'currentOrder':nodeOrder, + 'mdao_architecture':MDAO_architecture, + 'doe_settings': JSON.stringify(DOE_settings), + 'coupling_decomposition':coupling_decomposition, + 'allow_unconverged_couplings':allow_unconverged_couplings, + 'sessionId':sessionId}, + success: function(result) + { + if (result.includes("ERROR:")) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + else + { + var updatedData = {}; + updatedData = data; + var graphData = JSON.parse(result); + for (var i = 0; i < updatedData.graphs.length; i++) + { + if (graphID == updatedData.graphs[i].id) + { + updatedData.graphs[i] = graphData.graphs[0]; + } + } + + clearView(); + makeKadmosMenu(updatedData); + xdsm_script(updatedData,graphID); + + bootboxContent.message = "Success!" + kadmosSuccessMessage(bootboxContent) + } + }, + error: function(result) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + }); + kadmosHavePatience(xhr, bootboxContent) }) //#################################################################################################################### @@ -29350,7 +29504,9 @@ //aigner: Switch views between xdsm, edge bundles and sankey diagram //################################################################################################// - var quickMenuDiv = d3.select(".sankeyDiagramDiv").append("div").attr("class","quickMenuDiv").style("top","-10px") + var quickMenuDiv = d3.select(".sankeyDiagramDiv").append("div").attr("class","quickMenuDiv") + .style("top","-10px") + .style("margin-left","10pt") var changeViewButton = quickMenuDiv.append("button") .attr("class","btn btn-info") .attr("data-toggle","tooltip") @@ -29598,7 +29754,8 @@ }) } - d3.select(".graph_menu").moveToBack() + d3.select(".graph_menu").moveToBack() + d3.select(".quickMenuDiv").moveToBack() headerDiv.moveToBack() diff --git a/kadmos/vistoms/templates/info.html b/kadmos/vistoms/templates/info.html index 979c6239b..70ca44dd3 100644 --- a/kadmos/vistoms/templates/info.html +++ b/kadmos/vistoms/templates/info.html @@ -3,7 +3,7 @@ <div class="container"> <h1>Information</h1> <p>Please, refer to the following articles for more information on the KADMOS/VISTOMS interface: - <br>[1] Aigner, B., van Gent, I., La Rocca, G., Stumpf, E., Veldhuis, L.L.M., Using graph-based algorithms and data-driven documents for formulation and visualization of large MDO systems, CEAS Aeronautical Journal, 2018 + <br>[1] Aigner, B., van Gent, I., La Rocca, G., Stumpf, E., Veldhuis, L.L.M., Graph-based algorithms and data-driven documents for formulation and visualization of large MDO systems, CEAS Aeronautical Journal, 2018 <br>[2] van Gent, I., La Rocca, G., Veldhuis, L.L.M., Composing MDAO symphonies: graph-based generation and manipulation of large multidisciplinary systems, 18th AIAA/ISSMO Multidisciplinary Analysis and Optimization Conference, 2017 <br>[3] van Gent, I., Hoogreef, M.F.M., La Rocca, G., CMDOWS: A Proposed New Standard to Store and Exchange MDO Systems, CEAS Aeronautical Journal, 2018 <br>[4] van Gent, I. and Ciampa, P.D. and Aigner, B. and Jepsen, J. and La Rocca, G., Schut, E.J., Knowledge architecture supporting collaborative MDO in the AGILE paradigm, 18th AIAA/ISSMO Multidisciplinary Analysis and Optimization Conference, 2017 diff --git a/kadmos/vistoms/vistoms.py b/kadmos/vistoms/vistoms.py index b81c2046d..14dd325d5 100644 --- a/kadmos/vistoms/vistoms.py +++ b/kadmos/vistoms/vistoms.py @@ -16,6 +16,8 @@ from copy import deepcopy from datetime import datetime from shutil import copyfile +import numpy as np + import networkx as nx from flask import Flask, render_template, request, jsonify, send_from_directory, send_file from kadmos.cmdows.cmdows import find_cmdows_file @@ -730,14 +732,7 @@ def interface(debug=True, tempdir=None): path = session_folder graphFileName = TEMP_FILE + '_' + graphID + '.kdms' - mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms' - # TODO Benedikt: mpg is not used in this function, can it be removed, or should it be used? - 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 + graph = load(os.path.join(path, graphFileName), file_check_critical=False) check_result = graph._check_category_a() @@ -767,14 +762,8 @@ def interface(debug=True, tempdir=None): path = session_folder graphFileName = TEMP_FILE + '_' + graphID + '.kdms' - mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms' - # TODO Benedikt: mpg is not used in this function, can it be removed, or should it be used? - 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 + graph = load(os.path.join(path, graphFileName), file_check_critical=False) + check_result = graph._check_category_b() @@ -804,14 +793,7 @@ def interface(debug=True, tempdir=None): path = session_folder graphFileName = TEMP_FILE + '_' + graphID + '.kdms' - mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms' - # TODO Benedikt: mpg is not used in this function, can it be removed, or should it be used? - 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 + graph = load(os.path.join(path, graphFileName), file_check_critical=False) check_result = graph._check_category_c() @@ -1869,9 +1851,11 @@ def interface(debug=True, tempdir=None): fpg = FundamentalProblemGraph(graph) for data in variableData_py: if data['variableType'] == 'designVariable': + samples = data['samples'].split('[,;]') fpg.mark_as_design_variable(data['xPath'], nominal_value=float(data['nominalValue']), upper_bound=float(data['upperBound']), - lower_bound=float(data['lowerBound'])) + lower_bound=float(data['lowerBound']), + samples=samples if samples is not [] else None) elif data['variableType'] == 'objective': fpg.mark_as_objective(data['xPath']) elif data['variableType'] == 'constraint': @@ -1988,7 +1972,9 @@ def interface(debug=True, tempdir=None): # Cleaning of the graph needs to be done in a while loop, to entirely remove all unused elements another_run = True + counter = 0 while another_run: + counter += 1 another_run = False # Delete unused variables output_nodes = fpg.find_all_nodes(subcategory='all outputs') @@ -2002,7 +1988,6 @@ def interface(debug=True, tempdir=None): 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) @@ -2101,7 +2086,7 @@ def interface(debug=True, tempdir=None): if request.form['currentOrder'].split(',') != '': function_order = request.form['currentOrder'].split(',') mdao_architecture = request.form['mdao_architecture'] - doe_method = request.form['doe_method'] + doe_settings_py = json.loads(request.form['doe_settings']) coupling_decomposition = request.form['coupling_decomposition'] allow_unconverged_couplings_str = request.form['allow_unconverged_couplings'] if allow_unconverged_couplings_str == 'True': @@ -2109,6 +2094,23 @@ def interface(debug=True, tempdir=None): else: allow_unconverged_couplings = False + + # Check whether the value in each doe setting can be converted to an int, if not leave it a string + def is_int(s): + try: + float(s) + return True + except ValueError: + return False + # Convert the doe_settings_py to the correct format for KADMOS graph['problem_formulation']['doe_settings'] + doe_settings = {} + for doe_setting in doe_settings_py: + value = doe_setting['value'] + if is_int(value): + value = int(value) + doe_settings[doe_setting['name']] = value + + # First determine session folder session_id = request.form['sessionId'] session_folder = retrieve_session_folder(SESSIONS_CATALOG_FOLDER, session_id) @@ -2154,26 +2156,17 @@ def interface(debug=True, tempdir=None): fpg.graph['problem_formulation']['convergence_type'] = coupling_decomposition fpg.graph['problem_formulation']['allow_unconverged_couplings'] = allow_unconverged_couplings - # TODO Benedikt: Impose MDAO architecture does not always work + + # TODO Benedikt: Collaborative Optimization and Bliss2000 do not work yet if mdao_architecture in ['converged-DOE', 'unconverged-DOE']: - if doe_method not in fpg.OPTIONS_DOE_METHODS: + if doe_settings['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'] = {'method': doe_method} - if fpg.graph['problem_formulation']['doe_settings']['method'] in ['Latin hypercube design', - 'Monte Carlo design']: - fpg.graph['problem_formulation']['doe_settings']['seed'] = 6 - fpg.graph['problem_formulation']['doe_settings']['runs'] = 5 - elif fpg.graph['problem_formulation']['doe_settings']['method'] in ['Full factorial design']: - fpg.graph['problem_formulation']['doe_settings']['runs'] = 5 + fpg.graph['problem_formulation']['doe_settings'] = doe_settings 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 -- GitLab