|
2 | 2 |
|
3 | 3 | import BaseModelica |
4 | 4 | import Logging |
| 5 | +import ModelingToolkit |
| 6 | +import ModelingToolkitBase |
5 | 7 |
|
6 | 8 | """ |
7 | | - run_parse(bm_path, model_dir, model) → (success, time, error, ode_prob) |
| 9 | + run_parse(bm_path, model_dir, model) → NamedTuple |
8 | 10 |
|
9 | | -Parse a Base Modelica `.bmo` file with BaseModelica.jl and create an |
10 | | -`ODEProblem` from the `Experiment` annotation. |
11 | | -Writes a `<model>_parsing.log` file in `model_dir`. |
12 | | -Returns `nothing` as the fourth element on failure. |
| 11 | +Parse a Base Modelica `.bmo` file with BaseModelica.jl in three sub-steps and |
| 12 | +create an `ODEProblem` from the `Experiment` annotation. |
| 13 | +
|
| 14 | +Sub-steps timed and reported separately, each with its own log file: |
| 15 | +1. **ANTLR parser** — `<model>_antlr.log` — parses the `.bmo` file into an AST. |
| 16 | +2. **BM → MTK** — `<model>_mtk.log` — converts the AST into a |
| 17 | + `ModelingToolkit.System`. |
| 18 | +3. **ODEProblem** — `<model>_ode.log` — builds the `ODEProblem` using the |
| 19 | + `Experiment` annotation. |
| 20 | +
|
| 21 | +Returns a NamedTuple with fields: |
| 22 | +- `success`, `time`, `error` — overall result |
| 23 | +- `ode_prob` — the `ODEProblem` (or `nothing` on failure) |
| 24 | +- `antlr_success`, `antlr_time` |
| 25 | +- `mtk_success`, `mtk_time` |
| 26 | +- `ode_success`, `ode_time` |
13 | 27 | """ |
14 | 28 | function run_parse(bm_path::String, model_dir::String, |
15 | | - model::String)::Tuple{Bool,Float64,String,Any} |
16 | | - parse_success = false |
17 | | - parse_time = 0.0 |
18 | | - parse_error = "" |
| 29 | + model::String) |
| 30 | + antlr_success = false; antlr_time = 0.0; antlr_error = "" |
| 31 | + mtk_success = false; mtk_time = 0.0; mtk_error = "" |
| 32 | + ode_success = false; ode_time = 0.0; ode_error = "" |
19 | 33 | ode_prob = nothing |
| 34 | + package = nothing |
| 35 | + sys = nothing |
20 | 36 |
|
21 | 37 | isdir(model_dir) || mkpath(model_dir) |
22 | | - log_file = open(joinpath(model_dir, "$(model)_parsing.log"), "w") |
23 | | - stdout_pipe = Pipe() |
24 | | - println(log_file, "Model: $model") |
25 | | - logger = Logging.SimpleLogger(log_file, Logging.Debug) |
| 38 | + |
| 39 | + # ── Step 1: ANTLR parser ────────────────────────────────────────────────── |
| 40 | + log1 = open(joinpath(model_dir, "$(model)_antlr.log"), "w") |
| 41 | + pipe1 = Pipe() |
| 42 | + logger = Logging.SimpleLogger(log1, Logging.Debug) |
| 43 | + println(log1, "Model: $model") |
26 | 44 | t0 = time() |
27 | 45 | try |
28 | | - # create_odeproblem returns an ODEProblem using the Experiment |
29 | | - # annotation for StartTime/StopTime/Tolerance/Interval. |
30 | | - # Redirect Julia log output to the log file and stdout/stderr to a |
31 | | - # buffer so they can be appended after the summary lines. |
32 | | - ode_prob = redirect_stdout(stdout_pipe) do |
33 | | - redirect_stderr(stdout_pipe) do |
| 46 | + package = redirect_stdout(pipe1) do |
| 47 | + redirect_stderr(pipe1) do |
34 | 48 | Logging.with_logger(logger) do |
35 | | - BaseModelica.create_odeproblem(bm_path) |
| 49 | + BaseModelica.parse_file_antlr(bm_path) |
36 | 50 | end |
37 | 51 | end |
38 | 52 | end |
39 | | - parse_time = time() - t0 |
40 | | - parse_success = true |
| 53 | + antlr_time = time() - t0 |
| 54 | + antlr_success = true |
41 | 55 | catch e |
42 | | - parse_time = time() - t0 |
43 | | - parse_error = sprint(showerror, e, catch_backtrace()) |
| 56 | + antlr_time = time() - t0 |
| 57 | + antlr_error = sprint(showerror, e, catch_backtrace()) |
| 58 | + end |
| 59 | + close(pipe1.in) |
| 60 | + captured = read(pipe1.out, String) |
| 61 | + println(log1, "Time: $(round(antlr_time; digits=3)) s") |
| 62 | + println(log1, "Success: $antlr_success") |
| 63 | + isempty(captured) || print(log1, "\n--- Parser output ---\n", captured) |
| 64 | + isempty(antlr_error) || println(log1, "\n--- Error ---\n$antlr_error") |
| 65 | + close(log1) |
| 66 | + |
| 67 | + # ── Step 2: Base Modelica → ModelingToolkit ─────────────────────────────── |
| 68 | + if antlr_success |
| 69 | + log2 = open(joinpath(model_dir, "$(model)_mtk.log"), "w") |
| 70 | + pipe2 = Pipe() |
| 71 | + logger = Logging.SimpleLogger(log2, Logging.Debug) |
| 72 | + println(log2, "Model: $model") |
| 73 | + t0 = time() |
| 74 | + try |
| 75 | + sys = redirect_stdout(pipe2) do |
| 76 | + redirect_stderr(pipe2) do |
| 77 | + Logging.with_logger(logger) do |
| 78 | + BaseModelica.baseModelica_to_ModelingToolkit(package) |
| 79 | + end |
| 80 | + end |
| 81 | + end |
| 82 | + mtk_time = time() - t0 |
| 83 | + mtk_success = true |
| 84 | + catch e |
| 85 | + mtk_time = time() - t0 |
| 86 | + mtk_error = sprint(showerror, e, catch_backtrace()) |
| 87 | + end |
| 88 | + close(pipe2.in) |
| 89 | + captured = read(pipe2.out, String) |
| 90 | + println(log2, "Time: $(round(mtk_time; digits=3)) s") |
| 91 | + println(log2, "Success: $mtk_success") |
| 92 | + isempty(captured) || print(log2, "\n--- Parser output ---\n", captured) |
| 93 | + isempty(mtk_error) || println(log2, "\n--- Error ---\n$mtk_error") |
| 94 | + close(log2) |
44 | 95 | end |
45 | | - close(stdout_pipe.in) |
46 | | - captured = read(stdout_pipe.out, String) |
47 | | - println(log_file, "Time: $(round(parse_time; digits=3)) s") |
48 | | - println(log_file, "Success: $parse_success") |
49 | | - isempty(captured) || print(log_file, "\n--- Parser output ---\n", captured) |
50 | | - isempty(parse_error) || println(log_file, "\n--- Error ---\n$parse_error") |
51 | | - close(log_file) |
52 | | - |
53 | | - return parse_success, parse_time, parse_error, ode_prob |
| 96 | + |
| 97 | + # ── Step 3: ODEProblem generation ───────────────────────────────────────── |
| 98 | + if mtk_success |
| 99 | + log3 = open(joinpath(model_dir, "$(model)_ode.log"), "w") |
| 100 | + pipe3 = Pipe() |
| 101 | + logger = Logging.SimpleLogger(log3, Logging.Debug) |
| 102 | + println(log3, "Model: $model") |
| 103 | + t0 = time() |
| 104 | + try |
| 105 | + # Extract experiment annotation from the parsed package |
| 106 | + annotation = nothing |
| 107 | + try |
| 108 | + annotation = package.model.long_class_specifier.composition.annotation |
| 109 | + catch; end |
| 110 | + exp_params = BaseModelica.parse_experiment_annotation(annotation) |
| 111 | + |
| 112 | + ode_prob = redirect_stdout(pipe3) do |
| 113 | + redirect_stderr(pipe3) do |
| 114 | + Logging.with_logger(logger) do |
| 115 | + _mv = ModelingToolkitBase.MissingGuessValue.Constant(0.0) |
| 116 | + if !isnothing(exp_params) |
| 117 | + tspan = (exp_params.StartTime, exp_params.StopTime) |
| 118 | + extra_kw = isnothing(exp_params.Interval) ? |
| 119 | + (reltol = exp_params.Tolerance,) : |
| 120 | + (reltol = exp_params.Tolerance, |
| 121 | + saveat = exp_params.Interval) |
| 122 | + ModelingToolkit.ODEProblem(sys, [], tspan; |
| 123 | + missing_guess_value = _mv, extra_kw...) |
| 124 | + else |
| 125 | + ModelingToolkit.ODEProblem(sys, [], (0.0, 1.0); |
| 126 | + missing_guess_value = _mv) |
| 127 | + end |
| 128 | + end |
| 129 | + end |
| 130 | + end |
| 131 | + ode_time = time() - t0 |
| 132 | + ode_success = true |
| 133 | + catch e |
| 134 | + ode_time = time() - t0 |
| 135 | + ode_error = sprint(showerror, e, catch_backtrace()) |
| 136 | + end |
| 137 | + close(pipe3.in) |
| 138 | + captured = read(pipe3.out, String) |
| 139 | + println(log3, "Time: $(round(ode_time; digits=3)) s") |
| 140 | + println(log3, "Success: $ode_success") |
| 141 | + isempty(captured) || print(log3, "\n--- Parser output ---\n", captured) |
| 142 | + isempty(ode_error) || println(log3, "\n--- Error ---\n$ode_error") |
| 143 | + close(log3) |
| 144 | + end |
| 145 | + |
| 146 | + first_error = !isempty(antlr_error) ? antlr_error : |
| 147 | + !isempty(mtk_error) ? mtk_error : ode_error |
| 148 | + return ( |
| 149 | + success = ode_success, |
| 150 | + time = antlr_time + mtk_time + ode_time, |
| 151 | + error = first_error, |
| 152 | + ode_prob = ode_prob, |
| 153 | + antlr_success = antlr_success, |
| 154 | + antlr_time = antlr_time, |
| 155 | + mtk_success = mtk_success, |
| 156 | + mtk_time = mtk_time, |
| 157 | + ode_success = ode_success, |
| 158 | + ode_time = ode_time, |
| 159 | + ) |
54 | 160 | end |
0 commit comments