Skip to content

Commit 17ef964

Browse files
AnHeuermannclaude
andauthored
Filter simulation CSV to comparison signals only (#31)
Pass the list of signals to be compared (from comparisonSignals.txt or the reference CSV columns) to run_simulate before solving, so that only the relevant observed variables are written to disk. This avoids serialising thousands of algebraic variables when only a handful are actually verified. compare_with_reference gains a signals keyword that accepts the pre-resolved list, skipping the redundant file/CSV read it would otherwise perform itself. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 29aca16 commit 17ef964

3 files changed

Lines changed: 65 additions & 30 deletions

File tree

src/compare.jl

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ end
334334

335335
"""
336336
compare_with_reference(sol, ref_csv_path, model_dir, model;
337-
settings) → (total, pass, skip, diff_csv)
337+
settings, signals) → (total, pass, skip, diff_csv)
338338
339339
Compare a DifferentialEquations / MTK solution against the MAP-LIB reference CSV.
340340
@@ -354,33 +354,42 @@ is written whenever there are failures or skipped signals.
354354
355355
# Keyword arguments
356356
- `settings` — a `CompareSettings` instance controlling tolerances and the
357-
error function. Defaults to the module-level settings returned
358-
by `compare_settings()`. Use `configure_comparison!` to change
359-
the defaults, or pass a local `CompareSettings(...)` here.
357+
error function.
358+
- `signals` — explicit list of signal names to compare. When non-empty,
359+
overrides `comparisonSignals.txt` and the full reference CSV
360+
column list.
360361
"""
361362
function compare_with_reference(
362363
sol,
363364
ref_csv_path::String,
364365
model_dir::String,
365366
model::String;
366367
settings::CompareSettings = _CMP_SETTINGS,
368+
signals::Vector{String} = String[],
367369
)::Tuple{Int,Int,Int,String}
368370

369371
times, ref_data = _read_ref_csv(ref_csv_path)
370372
isempty(times) && return 0, 0, 0, ""
371373

372-
# Determine which signals to compare: prefer comparisonSignals.txt
373-
sig_file = joinpath(dirname(ref_csv_path), "comparisonSignals.txt")
374-
using_sig_file = isfile(sig_file)
375-
signals = if using_sig_file
376-
sigs = filter(s -> lowercase(s) != "time" && !isempty(s), strip.(readlines(sig_file)))
377-
sigs_missing = filter(s -> !haskey(ref_data, s), sigs)
378-
isempty(sigs_missing) || error("Signal(s) listed in comparisonSignals.txt not present in reference CSV: $(join(sigs_missing, ", "))")
379-
sigs
374+
# Determine which signals to compare.
375+
# Prefer the caller-supplied list; fall back to comparisonSignals.txt, then
376+
# all columns in the reference CSV.
377+
signals = if !isempty(signals)
378+
sigs_missing = filter(s -> !haskey(ref_data, s), signals)
379+
isempty(sigs_missing) || error("Signal(s) not present in reference CSV: $(join(sigs_missing, ", "))")
380+
signals
380381
else
381-
filter(k -> lowercase(k) != "time", collect(keys(ref_data)))
382+
sig_file = joinpath(dirname(ref_csv_path), "comparisonSignals.txt")
383+
if isfile(sig_file)
384+
sigs = filter(s -> lowercase(s) != "time" && !isempty(s), strip.(readlines(sig_file)))
385+
sigs_missing = filter(s -> !haskey(ref_data, s), sigs)
386+
isempty(sigs_missing) || error("Signal(s) listed in comparisonSignals.txt not present in reference CSV: $(join(sigs_missing, ", "))")
387+
sigs
388+
else
389+
filter(k -> lowercase(k) != "time", collect(keys(ref_data)))
390+
end
382391
end
383-
n_total = length(signals)
392+
n_total = length(signals)
384393

385394
# ── Build variable accessor map ──────────────────────────────────────────────
386395
# var_access: normalized name → Int (state index) or MTK symbolic (observed).

src/pipeline.jl

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,20 +76,34 @@ function test_model(omc::OMJulia.OMCSession, model::String, results_root::String
7676
par_ok || return ModelResult(
7777
model, true, exp_t, exp_err, false, par_t, par_err, false, 0.0, "", 0, 0, 0, "")
7878

79+
# Resolve reference CSV and comparison signals early so phase 3 can filter
80+
# the CSV output to only the signals that will actually be verified.
81+
ref_csv = isempty(ref_root) ? nothing : _ref_csv_path(ref_root, model)
82+
cmp_signals = if ref_csv !== nothing
83+
sig_file = joinpath(dirname(ref_csv), "comparisonSignals.txt")
84+
if isfile(sig_file)
85+
String.(filter(s -> lowercase(s) != "time" && !isempty(s), strip.(readlines(sig_file))))
86+
else
87+
_, ref_data = _read_ref_csv(ref_csv)
88+
filter(k -> lowercase(k) != "time", collect(keys(ref_data)))
89+
end
90+
else
91+
String[]
92+
end
93+
7994
# Phase 3 ──────────────────────────────────────────────────────────────────
80-
sim_ok, sim_t, sim_err, sol = run_simulate(ode_prob, model_dir, model; csv_max_size_mb)
95+
sim_ok, sim_t, sim_err, sol = run_simulate(ode_prob, model_dir, model;
96+
csv_max_size_mb, cmp_signals)
8197

8298
# Phase 4 (optional) ───────────────────────────────────────────────────────
8399
cmp_total, cmp_pass, cmp_skip, cmp_csv = 0, 0, 0, ""
84-
if sim_ok && !isempty(ref_root)
85-
ref_csv = _ref_csv_path(ref_root, model)
86-
if ref_csv !== nothing
87-
try
88-
cmp_total, cmp_pass, cmp_skip, cmp_csv =
89-
compare_with_reference(sol, ref_csv, model_dir, model)
90-
catch e
91-
@warn "Reference comparison failed for $model: $(sprint(showerror, e))"
92-
end
100+
if sim_ok && ref_csv !== nothing
101+
try
102+
cmp_total, cmp_pass, cmp_skip, cmp_csv =
103+
compare_with_reference(sol, ref_csv, model_dir, model;
104+
signals = cmp_signals)
105+
catch e
106+
@warn "Reference comparison failed for $model: $(sprint(showerror, e))"
93107
end
94108
end
95109

src/simulate.jl

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,24 @@ import ModelingToolkit
66
import Printf: @sprintf
77

88
"""
9-
run_simulate(ode_prob, model_dir, model; csv_max_size_mb) → (success, time, error, sol)
9+
run_simulate(ode_prob, model_dir, model; cmp_signals, csv_max_size_mb) → (success, time, error, sol)
1010
1111
Solve `ode_prob` with Rodas5P (stiff solver). On success, also writes the
12-
full solution as a CSV file `<Short>_sim.csv` in `model_dir`.
12+
solution as a CSV file `<Short>_sim.csv` in `model_dir`.
1313
Writes a `<model>_sim.log` file in `model_dir`.
1414
Returns `nothing` as the fourth element on failure.
1515
16-
CSV files larger than `csv_max_size_mb` MiB are deleted and replaced with a
16+
When `cmp_signals` is non-empty, only observed variables whose names appear in
17+
that list are written to the CSV, keeping file sizes small when only a subset
18+
of signals will be compared.
19+
20+
CSV files larger than `csv_max_size_mb` MiB are replaced with a
1721
`<Short>_sim.csv.toobig` marker so that the report can note the omission.
1822
"""
19-
function run_simulate(ode_prob, model_dir::String, model::String;
20-
csv_max_size_mb::Int = CSV_MAX_SIZE_MB)::Tuple{Bool,Float64,String,Any}
23+
function run_simulate(ode_prob, model_dir::String,
24+
model::String;
25+
cmp_signals ::Vector{String} = String[],
26+
csv_max_size_mb::Int = CSV_MAX_SIZE_MB)::Tuple{Bool,Float64,String,Any}
2127
sim_success = false
2228
sim_time = 0.0
2329
sim_error = ""
@@ -67,7 +73,13 @@ function run_simulate(ode_prob, model_dir::String, model::String;
6773
sys = sol.prob.f.sys
6874
vars = ModelingToolkit.unknowns(sys)
6975
obs_eqs = ModelingToolkit.observed(sys)
70-
obs_syms = [eq.lhs for eq in obs_eqs]
76+
# Only save observed variables that appear in cmp_signals.
77+
# This avoids writing thousands of algebraic variables to disk when
78+
# only a handful are actually verified during comparison.
79+
norm_cmp = Set(_normalize_var(s) for s in cmp_signals)
80+
obs_eqs_filtered = isempty(norm_cmp) ? obs_eqs :
81+
filter(eq -> _normalize_var(string(eq.lhs)) in norm_cmp, obs_eqs)
82+
obs_syms = [eq.lhs for eq in obs_eqs_filtered]
7183
col_names = vcat(
7284
[_clean_var_name(string(v)) for v in vars],
7385
[_clean_var_name(string(s)) for s in obs_syms],

0 commit comments

Comments
 (0)