From 87888ec654f8e8c7b02ce047ec33e50345dc5c0c Mon Sep 17 00:00:00 2001 From: AnHeuermann <38031952+AnHeuermann@users.noreply.github.com> Date: Tue, 24 Mar 2026 13:46:05 +0100 Subject: [PATCH 1/2] WIP --- .github/scripts/gen_landing_page.py | 26 ++++- Project.toml | 1 + src/parse_bm.jl | 172 ++++++++++++++++++++++------ src/pipeline.jl | 25 ++-- src/report.jl | 80 +++++++++---- src/summary.jl | 26 ++++- src/types.jl | 10 +- test/chua_circuit.jl | 10 +- 8 files changed, 268 insertions(+), 82 deletions(-) diff --git a/.github/scripts/gen_landing_page.py b/.github/scripts/gen_landing_page.py index 71153d2d2..ff9092d57 100644 --- a/.github/scripts/gen_landing_page.py +++ b/.github/scripts/gen_landing_page.py @@ -79,9 +79,15 @@ def load_runs(site_root: Path) -> list[dict]: except Exception: continue - models = data.get("models", []) + models = data.get("models", []) n = len(models) n_exp = sum(1 for m in models if m.get("export", False)) + # Sub-steps — fall back to overall "parse" flag for older summary.json files + # that predate the three-step split. + has_substeps = any("antlr" in m for m in models) + n_antlr = sum(1 for m in models if m.get("antlr", m.get("parse", False))) if has_substeps else None + n_mtk = sum(1 for m in models if m.get("mtk", m.get("parse", False))) if has_substeps else None + n_ode = sum(1 for m in models if m.get("ode", m.get("parse", False))) if has_substeps else None n_par = sum(1 for m in models if m.get("parse", False)) n_sim = sum(1 for m in models if m.get("sim", False)) @@ -100,6 +106,9 @@ def load_runs(site_root: Path) -> list[dict]: "omc_version": data.get("omc_version", "?"), "total": n, "n_exp": n_exp, + "n_antlr": n_antlr, + "n_mtk": n_mtk, + "n_ode": n_ode, "n_par": n_par, "n_sim": n_sim, "n_cmp": n_cmp, @@ -123,6 +132,11 @@ def _pct_cell(num: int, den: int) -> str: def render(runs: list[dict]) -> str: now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M UTC") + def _parse_sub_cell(n_sub, n_prev): + if n_sub is None: + return '—' + return _pct_cell(n_sub, n_prev) + if runs: rows = [] for r in runs: @@ -140,13 +154,15 @@ def render(runs: list[dict]) -> str: {r['date']} {r['duration']} {_pct_cell(r['n_exp'], r['total'])} - {_pct_cell(r['n_par'], r['n_exp'])} + {_parse_sub_cell(r['n_antlr'], r['n_exp'])} + {_parse_sub_cell(r['n_mtk'], r['n_antlr'] if r['n_antlr'] is not None else r['n_exp'])} + {_parse_sub_cell(r['n_ode'], r['n_mtk'] if r['n_mtk'] is not None else r['n_exp'])} {_pct_cell(r['n_sim'], r['n_par'])} {cmp_cell} """) rows_html = "\n".join(rows) else: - rows_html = ' No results yet.' + rows_html = ' No results yet.' return f"""\ @@ -180,7 +196,9 @@ def render(runs: list[dict]) -> str: Date Duration BM Export - BM Parse + ANTLR + BM→MTK + ODEProblem MTK Sim Ref Cmp diff --git a/Project.toml b/Project.toml index 21560b138..120bdab48 100644 --- a/Project.toml +++ b/Project.toml @@ -10,6 +10,7 @@ DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" +ModelingToolkitBase = "7771a370-6774-4173-bd38-47e70ca0b839" OMJulia = "0f4fe800-344e-11e9-2949-fb537ad918e1" Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" diff --git a/src/parse_bm.jl b/src/parse_bm.jl index dcaa2c935..3e8309c16 100644 --- a/src/parse_bm.jl +++ b/src/parse_bm.jl @@ -2,53 +2,159 @@ import BaseModelica import Logging +import ModelingToolkit +import ModelingToolkitBase """ - run_parse(bm_path, model_dir, model) → (success, time, error, ode_prob) + run_parse(bm_path, model_dir, model) → NamedTuple -Parse a Base Modelica `.bmo` file with BaseModelica.jl and create an -`ODEProblem` from the `Experiment` annotation. -Writes a `_parsing.log` file in `model_dir`. -Returns `nothing` as the fourth element on failure. +Parse a Base Modelica `.bmo` file with BaseModelica.jl in three sub-steps and +create an `ODEProblem` from the `Experiment` annotation. + +Sub-steps timed and reported separately, each with its own log file: +1. **ANTLR parser** — `_antlr.log` — parses the `.bmo` file into an AST. +2. **BM → MTK** — `_mtk.log` — converts the AST into a + `ModelingToolkit.System`. +3. **ODEProblem** — `_ode.log` — builds the `ODEProblem` using the + `Experiment` annotation. + +Returns a NamedTuple with fields: +- `success`, `time`, `error` — overall result +- `ode_prob` — the `ODEProblem` (or `nothing` on failure) +- `antlr_success`, `antlr_time` +- `mtk_success`, `mtk_time` +- `ode_success`, `ode_time` """ function run_parse(bm_path::String, model_dir::String, - model::String)::Tuple{Bool,Float64,String,Any} - parse_success = false - parse_time = 0.0 - parse_error = "" + model::String) + antlr_success = false; antlr_time = 0.0; antlr_error = "" + mtk_success = false; mtk_time = 0.0; mtk_error = "" + ode_success = false; ode_time = 0.0; ode_error = "" ode_prob = nothing + package = nothing + sys = nothing isdir(model_dir) || mkpath(model_dir) - log_file = open(joinpath(model_dir, "$(model)_parsing.log"), "w") - stdout_pipe = Pipe() - println(log_file, "Model: $model") - logger = Logging.SimpleLogger(log_file, Logging.Debug) + + # ── Step 1: ANTLR parser ────────────────────────────────────────────────── + log1 = open(joinpath(model_dir, "$(model)_antlr.log"), "w") + pipe1 = Pipe() + logger = Logging.SimpleLogger(log1, Logging.Debug) + println(log1, "Model: $model") t0 = time() try - # create_odeproblem returns an ODEProblem using the Experiment - # annotation for StartTime/StopTime/Tolerance/Interval. - # Redirect Julia log output to the log file and stdout/stderr to a - # buffer so they can be appended after the summary lines. - ode_prob = redirect_stdout(stdout_pipe) do - redirect_stderr(stdout_pipe) do + package = redirect_stdout(pipe1) do + redirect_stderr(pipe1) do Logging.with_logger(logger) do - BaseModelica.create_odeproblem(bm_path) + BaseModelica.parse_file_antlr(bm_path) end end end - parse_time = time() - t0 - parse_success = true + antlr_time = time() - t0 + antlr_success = true catch e - parse_time = time() - t0 - parse_error = sprint(showerror, e, catch_backtrace()) + antlr_time = time() - t0 + antlr_error = sprint(showerror, e, catch_backtrace()) + end + close(pipe1.in) + captured = read(pipe1.out, String) + println(log1, "Time: $(round(antlr_time; digits=3)) s") + println(log1, "Success: $antlr_success") + isempty(captured) || print(log1, "\n--- Parser output ---\n", captured) + isempty(antlr_error) || println(log1, "\n--- Error ---\n$antlr_error") + close(log1) + + # ── Step 2: Base Modelica → ModelingToolkit ─────────────────────────────── + if antlr_success + log2 = open(joinpath(model_dir, "$(model)_mtk.log"), "w") + pipe2 = Pipe() + logger = Logging.SimpleLogger(log2, Logging.Debug) + println(log2, "Model: $model") + t0 = time() + try + sys = redirect_stdout(pipe2) do + redirect_stderr(pipe2) do + Logging.with_logger(logger) do + BaseModelica.baseModelica_to_ModelingToolkit(package) + end + end + end + mtk_time = time() - t0 + mtk_success = true + catch e + mtk_time = time() - t0 + mtk_error = sprint(showerror, e, catch_backtrace()) + end + close(pipe2.in) + captured = read(pipe2.out, String) + println(log2, "Time: $(round(mtk_time; digits=3)) s") + println(log2, "Success: $mtk_success") + isempty(captured) || print(log2, "\n--- Parser output ---\n", captured) + isempty(mtk_error) || println(log2, "\n--- Error ---\n$mtk_error") + close(log2) end - close(stdout_pipe.in) - captured = read(stdout_pipe.out, String) - println(log_file, "Time: $(round(parse_time; digits=3)) s") - println(log_file, "Success: $parse_success") - isempty(captured) || print(log_file, "\n--- Parser output ---\n", captured) - isempty(parse_error) || println(log_file, "\n--- Error ---\n$parse_error") - close(log_file) - - return parse_success, parse_time, parse_error, ode_prob + + # ── Step 3: ODEProblem generation ───────────────────────────────────────── + if mtk_success + log3 = open(joinpath(model_dir, "$(model)_ode.log"), "w") + pipe3 = Pipe() + logger = Logging.SimpleLogger(log3, Logging.Debug) + println(log3, "Model: $model") + t0 = time() + try + # Extract experiment annotation from the parsed package + annotation = nothing + try + annotation = package.model.long_class_specifier.composition.annotation + catch; end + exp_params = BaseModelica.parse_experiment_annotation(annotation) + + ode_prob = redirect_stdout(pipe3) do + redirect_stderr(pipe3) do + Logging.with_logger(logger) do + _mv = ModelingToolkitBase.MissingGuessValue.Constant(0.0) + if !isnothing(exp_params) + tspan = (exp_params.StartTime, exp_params.StopTime) + extra_kw = isnothing(exp_params.Interval) ? + (reltol = exp_params.Tolerance,) : + (reltol = exp_params.Tolerance, + saveat = exp_params.Interval) + ModelingToolkit.ODEProblem(sys, [], tspan; + missing_guess_value = _mv, extra_kw...) + else + ModelingToolkit.ODEProblem(sys, [], (0.0, 1.0); + missing_guess_value = _mv) + end + end + end + end + ode_time = time() - t0 + ode_success = true + catch e + ode_time = time() - t0 + ode_error = sprint(showerror, e, catch_backtrace()) + end + close(pipe3.in) + captured = read(pipe3.out, String) + println(log3, "Time: $(round(ode_time; digits=3)) s") + println(log3, "Success: $ode_success") + isempty(captured) || print(log3, "\n--- Parser output ---\n", captured) + isempty(ode_error) || println(log3, "\n--- Error ---\n$ode_error") + close(log3) + end + + first_error = !isempty(antlr_error) ? antlr_error : + !isempty(mtk_error) ? mtk_error : ode_error + return ( + success = ode_success, + time = antlr_time + mtk_time + ode_time, + error = first_error, + ode_prob = ode_prob, + antlr_success = antlr_success, + antlr_time = antlr_time, + mtk_success = mtk_success, + mtk_time = mtk_time, + ode_success = ode_success, + ode_time = ode_time, + ) end diff --git a/src/pipeline.jl b/src/pipeline.jl index b253f61aa..bc32bd5f3 100644 --- a/src/pipeline.jl +++ b/src/pipeline.jl @@ -73,12 +73,20 @@ function test_model(omc::OMJulia.OMCSession, # Phase 1 ────────────────────────────────────────────────────────────────── exp_ok, exp_t, exp_err = run_export(omc, model, model_dir, bm_path) exp_ok || return ModelResult( - model, false, exp_t, exp_err, false, 0.0, "", false, 0.0, "", 0, 0, 0, "") + model, false, exp_t, exp_err, + false, 0.0, "", + false, 0.0, false, 0.0, false, 0.0, + false, 0.0, "", 0, 0, 0, "") # Phase 2 ────────────────────────────────────────────────────────────────── - par_ok, par_t, par_err, ode_prob = run_parse(bm_path, model_dir, model) - par_ok || return ModelResult( - model, true, exp_t, exp_err, false, par_t, par_err, false, 0.0, "", 0, 0, 0, "") + par = run_parse(bm_path, model_dir, model) + par.success || return ModelResult( + model, true, exp_t, exp_err, + false, par.time, par.error, + par.antlr_success, par.antlr_time, + par.mtk_success, par.mtk_time, + par.ode_success, par.ode_time, + false, 0.0, "", 0, 0, 0, "") # Resolve reference CSV and comparison signals early so phase 3 can filter # the CSV output to only the signals that will actually be verified. @@ -96,7 +104,7 @@ function test_model(omc::OMJulia.OMCSession, end # Phase 3 ────────────────────────────────────────────────────────────────── - sim_ok, sim_t, sim_err, sol = run_simulate(ode_prob, model_dir, model; + sim_ok, sim_t, sim_err, sol = run_simulate(par.ode_prob, model_dir, model; settings = sim_settings, csv_max_size_mb, cmp_signals) @@ -114,8 +122,11 @@ function test_model(omc::OMJulia.OMCSession, return ModelResult( model, - true, exp_t, exp_err, - true, par_t, par_err, + true, exp_t, exp_err, + true, par.time, par.error, + par.antlr_success, par.antlr_time, + par.mtk_success, par.mtk_time, + par.ode_success, par.ode_time, sim_ok, sim_t, sim_err, cmp_total, cmp_pass, cmp_skip, cmp_csv) end diff --git a/src/report.jl b/src/report.jl index 8ce87a243..ccef062b5 100644 --- a/src/report.jl +++ b/src/report.jl @@ -99,10 +99,12 @@ Write an `index.html` overview report to `results_root` and return its path. """ function generate_report(results::Vector{ModelResult}, results_root::String, info::RunInfo; csv_max_size_mb::Int = CSV_MAX_SIZE_MB) - n = length(results) - n_exp = count(r -> r.export_success, results) - n_par = count(r -> r.parse_success, results) - n_sim = count(r -> r.sim_success, results) + n = length(results) + n_exp = count(r -> r.export_success, results) + n_antlr = count(r -> r.antlr_success, results) + n_mtk = count(r -> r.mtk_success, results) + n_ode = count(r -> r.ode_success, results) + n_sim = count(r -> r.sim_success, results) # Comparison summary (only models where cmp_total > 0) cmp_results = filter(r -> r.cmp_total > 0, results) @@ -114,13 +116,31 @@ function generate_report(results::Vector{ModelResult}, results_root::String, cmp_summary_row = n_cmp_models > 0 ? """ Reference Comparison (MAP-LIB)$n_cmp_pass$n_cmp_models$(pct(n_cmp_pass,n_cmp_models))""" : "" - rows = join([""" + rows = join([begin + antlr_status = !r.export_success ? "na" : (r.antlr_success ? "pass" : "fail") + mtk_status = !r.antlr_success ? "na" : (r.mtk_success ? "pass" : "fail") + ode_status = !r.mtk_success ? "na" : (r.ode_success ? "pass" : "fail") + + antlr_cell = antlr_status == "na" ? """—""" : + _status_cell(r.antlr_success, r.antlr_time, + rel_log_file_or_nothing(results_root, r.name, "antlr")) + mtk_cell = mtk_status == "na" ? """—""" : + _status_cell(r.mtk_success, r.mtk_time, + rel_log_file_or_nothing(results_root, r.name, "mtk")) + ode_cell = ode_status == "na" ? """—""" : + _status_cell(r.ode_success, r.ode_time, + rel_log_file_or_nothing(results_root, r.name, "ode")) + + """ $(r.name).bmo $(_status_cell(r.export_success, r.export_time, rel_log_file_or_nothing(results_root, r.name, "export"))) - $(_status_cell(r.parse_success, r.parse_time, rel_log_file_or_nothing(results_root, r.name, "parsing"))) + $(antlr_cell) + $(mtk_cell) + $(ode_cell) $(_status_cell(r.sim_success, r.sim_time, rel_log_file_or_nothing(results_root, r.name, "sim"))) $(_cmp_cell(r, results_root, csv_max_size_mb)) - """ for r in results], "\n") + """ + end for r in results], "\n") bm_sha_link = isempty(info.bm_sha) ? "" : """ ($(info.bm_sha))""" @@ -168,9 +188,11 @@ Total run time: $(time_str)

- - - $cmp_summary_row + + + + + $cmp_summary_row
StagePassedTotalRate
Base Modelica Export (OpenModelica)$n_exp$n $(pct(n_exp,n))
Parsing (BaseModelica.jl) $n_par$n_exp$(pct(n_par,n_exp))
Simulation (MTK.jl) $n_sim$n_par$(pct(n_sim,n_par))
Base Modelica Export (OpenModelica)$n_exp$n $(pct(n_exp,n))
Base Modelica Parse - ANTLR $n_antlr$n_exp$(pct(n_antlr,n_exp))
Base Modelica Parse - BM→MTK $n_mtk$n_antlr$(pct(n_mtk,n_antlr))
Base Modelica Parse - ODEProblem $n_ode$n_mtk $(pct(n_ode,n_mtk))
Simulation (MTK.jl) $n_sim$n_ode $(pct(n_sim,n_ode))
@@ -178,16 +200,20 @@ Total run time: $(time_str)

- - - + + + + + - - - - + + + + + + @@ -206,17 +232,21 @@ function applyFilters() { nameInput.classList.add('invalid'); return; } - var exp = document.getElementById('f-exp').value; - var par = document.getElementById('f-par').value; - var sim = document.getElementById('f-sim').value; - var cmp = document.getElementById('f-cmp').value; + var exp = document.getElementById('f-exp').value; + var antlr = document.getElementById('f-antlr').value; + var mtk = document.getElementById('f-mtk').value; + var ode = document.getElementById('f-ode').value; + var sim = document.getElementById('f-sim').value; + var cmp = document.getElementById('f-cmp').value; document.querySelectorAll('#model-rows tr').forEach(function(row) { var name = row.cells[0] ? row.cells[0].textContent : ''; var show = (!nameRe || nameRe.test(name)) && - (exp === 'all' || row.dataset.exp === exp) && - (par === 'all' || row.dataset.par === par) && - (sim === 'all' || row.dataset.sim === sim) && - (cmp === 'all' || row.dataset.cmp === cmp); + (exp === 'all' || row.dataset.exp === exp) && + (antlr === 'all' || row.dataset.antlr === antlr) && + (mtk === 'all' || row.dataset.mtk === mtk) && + (ode === 'all' || row.dataset.ode === ode) && + (sim === 'all' || row.dataset.sim === sim) && + (cmp === 'all' || row.dataset.cmp === cmp); row.style.display = show ? '' : 'none'; }); } diff --git a/src/summary.jl b/src/summary.jl index 847a9c8e7..b7f441169 100644 --- a/src/summary.jl +++ b/src/summary.jl @@ -43,6 +43,12 @@ function write_summary( "\"export_time\":$(@sprintf "%.3f" r.export_time)," * "\"parse\":$(r.parse_success)," * "\"parse_time\":$(@sprintf "%.3f" r.parse_time)," * + "\"antlr\":$(r.antlr_success)," * + "\"antlr_time\":$(@sprintf "%.3f" r.antlr_time)," * + "\"mtk\":$(r.mtk_success)," * + "\"mtk_time\":$(@sprintf "%.3f" r.mtk_time)," * + "\"ode\":$(r.ode_success)," * + "\"ode_time\":$(@sprintf "%.3f" r.ode_time)," * "\"sim\":$(r.sim_success)," * "\"sim_time\":$(@sprintf "%.3f" r.sim_time)," * "\"cmp_total\":$(r.cmp_total)," * @@ -77,7 +83,9 @@ Parsed contents of a single `summary.json` file. - `total_time_s` — wall-clock duration of the full test run in seconds - `solver` — fully-qualified solver name, e.g. `"DifferentialEquations.Rodas5P"` - `models` — vector of per-model dicts; each has keys - `"name"`, `"export"`, `"parse"`, `"sim"`, `"cmp_total"`, `"cmp_pass"` + `"name"`, `"export"`, `"parse"`, + `"antlr"`, `"mtk"`, `"ode"` (parse sub-steps), + `"sim"`, `"cmp_total"`, `"cmp_pass"` """ struct RunSummary library :: String @@ -124,7 +132,7 @@ function load_summary(results_root::String)::Union{RunSummary,Nothing} models = Dict{String,Any}[] for m in eachmatch( - r"\{\"name\":\"([^\"]*)\",\"export\":(true|false),\"export_time\":([\d.]+),\"parse\":(true|false),\"parse_time\":([\d.]+),\"sim\":(true|false),\"sim_time\":([\d.]+),\"cmp_total\":(\d+),\"cmp_pass\":(\d+)\}", + r"\{\"name\":\"([^\"]*)\",\"export\":(true|false),\"export_time\":([\d.]+),\"parse\":(true|false),\"parse_time\":([\d.]+),\"antlr\":(true|false),\"antlr_time\":([\d.]+),\"mtk\":(true|false),\"mtk_time\":([\d.]+),\"ode\":(true|false),\"ode_time\":([\d.]+),\"sim\":(true|false),\"sim_time\":([\d.]+),\"cmp_total\":(\d+),\"cmp_pass\":(\d+)\}", txt) push!(models, Dict{String,Any}( "name" => string(m.captures[1]), @@ -132,10 +140,16 @@ function load_summary(results_root::String)::Union{RunSummary,Nothing} "export_time" => parse(Float64, m.captures[3]), "parse" => m.captures[4] == "true", "parse_time" => parse(Float64, m.captures[5]), - "sim" => m.captures[6] == "true", - "sim_time" => parse(Float64, m.captures[7]), - "cmp_total" => parse(Int, m.captures[8]), - "cmp_pass" => parse(Int, m.captures[9]), + "antlr" => m.captures[6] == "true", + "antlr_time" => parse(Float64, m.captures[7]), + "mtk" => m.captures[8] == "true", + "mtk_time" => parse(Float64, m.captures[9]), + "ode" => m.captures[10] == "true", + "ode_time" => parse(Float64, m.captures[11]), + "sim" => m.captures[12] == "true", + "sim_time" => parse(Float64, m.captures[13]), + "cmp_total" => parse(Int, m.captures[14]), + "cmp_pass" => parse(Int, m.captures[15]), )) end return RunSummary( diff --git a/src/types.jl b/src/types.jl index 18704c5ae..843237033 100644 --- a/src/types.jl +++ b/src/types.jl @@ -106,9 +106,15 @@ struct ModelResult export_success :: Bool export_time :: Float64 export_error :: String - parse_success :: Bool - parse_time :: Float64 + parse_success :: Bool # true iff all three parse sub-steps succeeded + parse_time :: Float64 # total parse time (sum of three sub-steps) parse_error :: String + antlr_success :: Bool # Phase 2a: ANTLR parser + antlr_time :: Float64 + mtk_success :: Bool # Phase 2b: Base Modelica → ModelingToolkit conversion + mtk_time :: Float64 + ode_success :: Bool # Phase 2c: ODEProblem generation + ode_time :: Float64 sim_success :: Bool sim_time :: Float64 sim_error :: String diff --git a/test/chua_circuit.jl b/test/chua_circuit.jl index 1f3ffcbcb..e98f95150 100644 --- a/test/chua_circuit.jl +++ b/test/chua_circuit.jl @@ -15,12 +15,12 @@ exp_ok || @warn "Export error: $exp_err" if exp_ok - par_ok, _, par_err, ode_prob = run_parse(bm_path, model_dir, TEST_MODEL_CHUA) - @test par_ok - par_ok || @warn "Parse error: $par_err" + par = run_parse(bm_path, model_dir, TEST_MODEL_CHUA) + @test par.success + par.success || @warn "Parse error: $(par.error)" - if par_ok - sim_ok, _, sim_err, _ = run_simulate(ode_prob, model_dir, TEST_MODEL_CHUA) + if par.success + sim_ok, _, sim_err, _ = run_simulate(par.ode_prob, model_dir, TEST_MODEL_CHUA) @test sim_ok sim_ok || @warn "Simulation error: $sim_err" end From c260322db4f25f1cb3b18e7998d54ff1d8e48fbf Mon Sep 17 00:00:00 2001 From: AnHeuermann <38031952+AnHeuermann@users.noreply.github.com> Date: Tue, 24 Mar 2026 13:57:34 +0100 Subject: [PATCH 2/2] Finer error reports for parsing Base Modelica MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added separate log files and timings for steps of parsing: * Phase 2a: ANTLR parser * Phase 2b: Base Modelica → ModelingToolkit conversion * Phase 2c: ODEProblem generation * Update HTML report and overview. * Updated summary.json Co-authored-by: Claude Sonnet 4.6 --- src/report.jl | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/report.jl b/src/report.jl index ccef062b5..e64f7c1ab 100644 --- a/src/report.jl +++ b/src/report.jl @@ -120,6 +120,7 @@ function generate_report(results::Vector{ModelResult}, results_root::String, antlr_status = !r.export_success ? "na" : (r.antlr_success ? "pass" : "fail") mtk_status = !r.antlr_success ? "na" : (r.mtk_success ? "pass" : "fail") ode_status = !r.mtk_success ? "na" : (r.ode_success ? "pass" : "fail") + sim_status = !r.ode_success ? "na" : (r.sim_success ? "pass" : "fail") antlr_cell = antlr_status == "na" ? """""" : _status_cell(r.antlr_success, r.antlr_time, @@ -130,14 +131,17 @@ function generate_report(results::Vector{ModelResult}, results_root::String, ode_cell = ode_status == "na" ? """""" : _status_cell(r.ode_success, r.ode_time, rel_log_file_or_nothing(results_root, r.name, "ode")) + sim_cell = sim_status == "na" ? """""" : + _status_cell(r.sim_success, r.sim_time, + rel_log_file_or_nothing(results_root, r.name, "sim")) - """ + """ $(_status_cell(r.export_success, r.export_time, rel_log_file_or_nothing(results_root, r.name, "export"))) $(antlr_cell) $(mtk_cell) $(ode_cell) - $(_status_cell(r.sim_success, r.sim_time, rel_log_file_or_nothing(results_root, r.name, "sim"))) + $(sim_cell) $(_cmp_cell(r, results_root, csv_max_size_mb)) """ end for r in results], "\n") @@ -164,7 +168,7 @@ function generate_report(results::Vector{ModelResult}, results_root::String, td.ok { background: #d4edda; color: #155724; } td.partial { background: #fff3cd; color: #856404; } td.fail { background: #f8d7da; color: #721c24; } - td.na { color: #888; } + td.na { background: #f8d7da; color: #888; } a { color: #0366d6; text-decoration: none; } a:hover { text-decoration: underline; } .filter-row th { background: #f5f5f5; }
Model BM ExportBM ParseMTK SimRef CmpANTLRBM→MTKODEProblemMTK SimulationResult Comparison
$(r.name).bmo