From d8127eb3d704369f6a5c2c864d9c81f57b9f450e Mon Sep 17 00:00:00 2001 From: Lwiisport Date: Wed, 15 Jul 2026 15:39:08 -0400 Subject: [PATCH 1/4] LGO - Int and Ext transition conditions fix --- GUI/js/main.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GUI/js/main.js b/GUI/js/main.js index 08fa71b..855a988 100644 --- a/GUI/js/main.js +++ b/GUI/js/main.js @@ -1321,7 +1321,7 @@ function main(container) { condInput.style.width = "80%"; if (isOtherwise) condInput.disabled = true; - condInput.addEventListener("input", () => { + condInput.addEventListener("focusout", () => { const newCond = condInput.value.trim(); if (!newCond || newCond === condition) return; if (deltaIntObj[newCond]) return; @@ -1416,7 +1416,7 @@ function main(container) { condInput.style.width = "80%"; if (isOtherwise) condInput.disabled = true; - condInput.addEventListener("input", () => { + condInput.addEventListener("focusout", () => { const newCond = condInput.value.trim(); if (!newCond || newCond === condition) return; if (deltaExtObj[newCond]) return; From b9926b7d8d17d3312024fda425afa5c02cb8f13e Mon Sep 17 00:00:00 2001 From: Lwiisport Date: Thu, 16 Jul 2026 08:32:51 -0400 Subject: [PATCH 2/4] LGO - add "Trace Viewer" button. --- GUI/index.html | 1 + GUI/js/experiment-design.js | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/GUI/index.html b/GUI/index.html index f009f2f..3633508 100644 --- a/GUI/index.html +++ b/GUI/index.html @@ -251,6 +251,7 @@

DEVS Graph Tool

Simulation Output
+ diff --git a/GUI/js/experiment-design.js b/GUI/js/experiment-design.js index 84a94c5..f6e442b 100644 --- a/GUI/js/experiment-design.js +++ b/GUI/js/experiment-design.js @@ -40,6 +40,7 @@ export function setupExperimentSidebar(graph) { const runExpBtn = document.getElementById("runExperimentBtn"); const clearOutputBtn = document.getElementById("clearOutputBtn"); + const traceViewerBtn = document.getElementById("traceViewerBtn"); const exportCsvBtn = document.getElementById("exportCsvBtn"); const validateBtn = document.getElementById("validateOutputBtn"); const modeSelect = document.getElementById("validationMode"); @@ -227,6 +228,10 @@ export function setupExperimentSidebar(graph) { setBottomOutputMessage(""); }); + traceViewerBtn?.addEventListener("click", () => { + window.open("https://devssim.carleton.ca/trace-viewer/index.html", "_blank"); + }); + exportCsvBtn?.addEventListener("click", () => { const csv = window.__LAST_CSV_OUTPUT || ""; From 5895cf4aababdbc28204c63c61882dee11126af2 Mon Sep 17 00:00:00 2001 From: Lwiisport Date: Thu, 16 Jul 2026 11:17:47 -0400 Subject: [PATCH 3/4] LGO - Simulation output button fix --- GUI/js/experiment-design.js | 144 ++++++++++++++++++------------------ GUI/js/main.js | 6 +- 2 files changed, 78 insertions(+), 72 deletions(-) diff --git a/GUI/js/experiment-design.js b/GUI/js/experiment-design.js index f6e442b..83d1a06 100644 --- a/GUI/js/experiment-design.js +++ b/GUI/js/experiment-design.js @@ -27,6 +27,79 @@ function setBottomOutputMessage(text) { container.innerHTML = `
${escapeHtml(text)}
`; } +export function setSimulationOutputButtons() { + const clearOutputBtn = document.getElementById("clearOutputBtn"); + const traceViewerBtn = document.getElementById("traceViewerBtn"); + const exportCsvBtn = document.getElementById("exportCsvBtn"); + const validateBtn = document.getElementById("validateOutputBtn"); + const modeSelect = document.getElementById("validationMode"); + const fileInput = document.getElementById("fileInput"); + const out = document.getElementById("experimentOutput"); + + clearOutputBtn?.addEventListener("click", () => { + if (out) out.textContent = ""; + setBottomOutputMessage(""); + }); + + traceViewerBtn?.addEventListener("click", () => { + window.open("https://devssim.carleton.ca/trace-viewer/index.html", "_blank"); + }); + + exportCsvBtn?.addEventListener("click", () => { + const csv = window.__LAST_CSV_OUTPUT || ""; + + if (!csv.trim()) { + alert("No simulation output to export."); + return; + } + + const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" }); + const url = URL.createObjectURL(blob); + + const a = document.createElement("a"); + a.href = url; + a.download = "simulation_output.csv"; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + + URL.revokeObjectURL(url); + }); + + validateBtn?.addEventListener("click", async () => { + try { + const mode = modeSelect.value; + + if (mode === "file") { + fileInput.click(); + + fileInput.onchange = async () => { + const file = fileInput.files[0]; + if (!file) return; + + const formData = new FormData(); + formData.append("file", file); + formData.append("mode", "file"); + formData.append("tolerance", "0.1"); + + setBottomOutputMessage("Running validation..."); + + const res = await fetch("http://localhost:8002/validate", { + method: "POST", + body: formData + }); + + const result = await res.text(); + setBottomOutputMessage(result); + }; + } + } catch (err) { + console.error(err); + setBottomOutputMessage("Validation failed: " + err.message); + } + }); +} + export function setupExperimentSidebar(graph) { const cm = new ConversionManager(graph); @@ -39,13 +112,6 @@ export function setupExperimentSidebar(graph) { const genExpJsonBtn = document.getElementById("generateExperimentJsonBtn"); const runExpBtn = document.getElementById("runExperimentBtn"); - const clearOutputBtn = document.getElementById("clearOutputBtn"); - const traceViewerBtn = document.getElementById("traceViewerBtn"); - const exportCsvBtn = document.getElementById("exportCsvBtn"); - const validateBtn = document.getElementById("validateOutputBtn"); - const modeSelect = document.getElementById("validationMode"); - const fileInput = document.getElementById("fileInput"); - const folderInput = document.getElementById("folderInput"); const out = document.getElementById("experimentOutput"); const propsTab = document.getElementById("propertiesTab"); @@ -223,70 +289,6 @@ export function setupExperimentSidebar(graph) { }) ); - clearOutputBtn?.addEventListener("click", () => { - if (out) out.textContent = ""; - setBottomOutputMessage(""); - }); - - traceViewerBtn?.addEventListener("click", () => { - window.open("https://devssim.carleton.ca/trace-viewer/index.html", "_blank"); - }); - - exportCsvBtn?.addEventListener("click", () => { - const csv = window.__LAST_CSV_OUTPUT || ""; - - if (!csv.trim()) { - alert("No simulation output to export."); - return; - } - - const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" }); - const url = URL.createObjectURL(blob); - - const a = document.createElement("a"); - a.href = url; - a.download = "simulation_output.csv"; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); - - URL.revokeObjectURL(url); - }); - -validateBtn?.addEventListener("click", async () => { - try { - const mode = modeSelect.value; - - if (mode === "file") { - fileInput.click(); - - fileInput.onchange = async () => { - const file = fileInput.files[0]; - if (!file) return; - - const formData = new FormData(); - formData.append("file", file); - formData.append("mode", "file"); - formData.append("tolerance", "0.1"); - - setBottomOutputMessage("Running validation..."); - - const res = await fetch("http://localhost:8002/validate", { - method: "POST", - body: formData - }); - - const result = await res.text(); - setBottomOutputMessage(result); - }; - } - - } catch (err) { - console.error(err); - setBottomOutputMessage("Validation failed: " + err.message); - } -}); - function getCoupledPortsByUid(uid) { const uos = cm.getUserObjects(); const coupled = uos.find( diff --git a/GUI/js/main.js b/GUI/js/main.js index 855a988..bfabe41 100644 --- a/GUI/js/main.js +++ b/GUI/js/main.js @@ -6,10 +6,14 @@ import { exportGraphImage } from './image-utils.js'; import { ConversionManager } from './conversions.js'; import { shortcuts } from './shortcuts.js'; -import { setupExperimentSidebar } from "./experiment-design.js"; +import { setupExperimentSidebar, setSimulationOutputButtons } from "./experiment-design.js"; window.customDataTypes = window.customDataTypes || []; +document.addEventListener("DOMContentLoaded", () => { + setSimulationOutputButtons(); +}); + function repairLoadedUserObjects(graph) { const model = graph.getModel(); From 60f8d87fd103c37a2a20105d64c3cbf993d12511 Mon Sep 17 00:00:00 2001 From: Lwiisport Date: Wed, 29 Jul 2026 14:47:47 -0400 Subject: [PATCH 4/4] LGO - bug fix string values --- DEVSMap_to_Cadmium_Parser/helper.py | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/DEVSMap_to_Cadmium_Parser/helper.py b/DEVSMap_to_Cadmium_Parser/helper.py index caff43d..7036acf 100644 --- a/DEVSMap_to_Cadmium_Parser/helper.py +++ b/DEVSMap_to_Cadmium_Parser/helper.py @@ -23,6 +23,25 @@ def prefix_states(text, list_of_state_variables): import re +def normalize_string_literal(value): + """ + Convert DEVSMap string literals into valid C++ string literals. + Supports both single-quoted values and already double-quoted values. + """ + if not isinstance(value, str): + return value + + stripped = value.strip() + if len(stripped) >= 2 and stripped[0] == stripped[-1] and stripped[0] == '"': + return stripped + + if len(stripped) >= 2 and stripped[0] == stripped[-1] and stripped[0] == "'": + inner = stripped[1:-1] + return f'"{inner}"' + + return value + + def prefix_states(text, list_of_state_variables): """ Prefix bare state variable names with 'state.' but do not @@ -107,7 +126,8 @@ def simple_conditional_statement(key, value): key (str): The state variable being assigned. value (str): The value to assign to the state variable. ''' - return '\t\t' + key + ' = ' + value + ';\n' + normalized_value = normalize_string_literal(value) + return '\t\t' + key + ' = ' + normalized_value + ';\n' """ # Recursive function to write conditional blocks based on nested JSON structure @@ -193,11 +213,13 @@ def build_conditional_statements_helper(data, indent=2): if isinstance(value, dict): if all(not isinstance(v, dict) for v in value.values()): for var, expr in value.items(): - conditions += INDENT * (indent + 1) + f'{var} = {expr};\n' + normalized_expr = normalize_string_literal(expr) + conditions += INDENT * (indent + 1) + f'{var} = {normalized_expr};\n' else: conditions += build_conditional_statements_helper(value, indent + 1) else: - conditions += INDENT * (indent + 1) + f'{key} = {value};\n' + normalized_value = normalize_string_literal(value) + conditions += INDENT * (indent + 1) + f'{key} = {normalized_value};\n' conditions += INDENT * indent + '}\n'