dynamic-systems-testing-framework 1.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. dynamic_systems_testing_framework-1.0.1/.gitignore +89 -0
  2. dynamic_systems_testing_framework-1.0.1/LICENSE +21 -0
  3. dynamic_systems_testing_framework-1.0.1/PKG-INFO +266 -0
  4. dynamic_systems_testing_framework-1.0.1/README.md +226 -0
  5. dynamic_systems_testing_framework-1.0.1/pyproject.toml +188 -0
  6. dynamic_systems_testing_framework-1.0.1/src/dstf/__init__.py +41 -0
  7. dynamic_systems_testing_framework-1.0.1/src/dstf/__main__.py +10 -0
  8. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/__init__.py +13 -0
  9. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/builtin/__init__.py +32 -0
  10. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/builtin/accept.py +205 -0
  11. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/builtin/edit_criteria.py +479 -0
  12. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/builtin/edit_family.py +228 -0
  13. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/builtin/edit_on_plot.py +1354 -0
  14. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/builtin/edit_tree.py +1399 -0
  15. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/builtin/enqueue.py +144 -0
  16. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/capabilities.py +463 -0
  17. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/errors.py +49 -0
  18. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/family_rows.py +526 -0
  19. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/forms.py +631 -0
  20. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/layout.py +104 -0
  21. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/live_rows.py +337 -0
  22. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/live_runs.py +385 -0
  23. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/needle.py +127 -0
  24. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/picker_rows.py +92 -0
  25. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/queue_rows.py +354 -0
  26. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/session.py +3016 -0
  27. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/__init__.py +9 -0
  28. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/actions.py +702 -0
  29. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/app.py +53 -0
  30. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/drawer_controls.py +190 -0
  31. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/family_fold.py +468 -0
  32. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/figure_hook.py +249 -0
  33. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/grips.js +1000 -0
  34. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/header.py +783 -0
  35. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/live_view.py +93 -0
  36. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/picker.py +267 -0
  37. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/placing.py +122 -0
  38. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/plot_card.py +1171 -0
  39. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/queue_panel.py +433 -0
  40. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/rail.py +593 -0
  41. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/shell.py +528 -0
  42. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/stats_card.py +501 -0
  43. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/strip.py +204 -0
  44. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/style.py +721 -0
  45. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/suite.py +277 -0
  46. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/suite_grid.js +414 -0
  47. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/suite_grid.py +373 -0
  48. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/tab_theme.py +110 -0
  49. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/tabstate.py +146 -0
  50. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/test_list.py +179 -0
  51. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/test_page.py +1404 -0
  52. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/tree_card.py +1171 -0
  53. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/variables_drawer.py +589 -0
  54. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/shell/widgets.py +188 -0
  55. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/situation.py +287 -0
  56. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/spec_document.py +215 -0
  57. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/spec_preview.py +83 -0
  58. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/suite_rows.py +99 -0
  59. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/tree_move.py +516 -0
  60. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/tree_pointer.py +33 -0
  61. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/tree_text.py +61 -0
  62. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/typed_number.js +64 -0
  63. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/typed_number.py +76 -0
  64. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/unscorable.py +141 -0
  65. dynamic_systems_testing_framework-1.0.1/src/dstf/authoring/variable_rows.py +216 -0
  66. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/__init__.py +283 -0
  67. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/base.py +1117 -0
  68. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/common/__init__.py +1 -0
  69. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/common/json_driver.py +484 -0
  70. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/common/live_mat.py +369 -0
  71. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/common/mat_reader.py +632 -0
  72. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/common/proc_kill.py +238 -0
  73. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/common/proc_output.py +20 -0
  74. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/common/result_files.py +109 -0
  75. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/common/result_variables.py +329 -0
  76. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/common/statistics.py +39 -0
  77. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/cross_backend.py +193 -0
  78. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/dymola/__init__.py +5 -0
  79. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/dymola/backend.py +776 -0
  80. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/dymola/interface_loader.py +241 -0
  81. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/dymola/log_parser.py +396 -0
  82. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/dymola/persistent_backend.py +949 -0
  83. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/fmpy/__init__.py +11 -0
  84. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/fmpy/backend.py +443 -0
  85. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/julia/__init__.py +27 -0
  86. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/julia/backend.py +156 -0
  87. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/julia/persistent_backend.py +541 -0
  88. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/julia/run_persistent.jl +167 -0
  89. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/julia/run_test.jl +146 -0
  90. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/openmodelica/__init__.py +21 -0
  91. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/openmodelica/backend.py +368 -0
  92. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/openmodelica/init_xml.py +76 -0
  93. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/openmodelica/log_parser.py +119 -0
  94. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/openmodelica/mos_generator.py +228 -0
  95. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/openmodelica/persistent_backend.py +1045 -0
  96. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/openmodelica/session_loader.py +63 -0
  97. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/persistent.py +1811 -0
  98. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/pool.py +602 -0
  99. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/progress.py +395 -0
  100. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/python/__init__.py +11 -0
  101. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/python/backend.py +141 -0
  102. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/python/run_test.py +141 -0
  103. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/run_metadata.py +103 -0
  104. dynamic_systems_testing_framework-1.0.1/src/dstf/backends/types.py +310 -0
  105. dynamic_systems_testing_framework-1.0.1/src/dstf/cli/__init__.py +12 -0
  106. dynamic_systems_testing_framework-1.0.1/src/dstf/cli/author_cmd.py +61 -0
  107. dynamic_systems_testing_framework-1.0.1/src/dstf/cli/baseline_cmds.py +341 -0
  108. dynamic_systems_testing_framework-1.0.1/src/dstf/cli/common.py +231 -0
  109. dynamic_systems_testing_framework-1.0.1/src/dstf/cli/diag_cmds.py +350 -0
  110. dynamic_systems_testing_framework-1.0.1/src/dstf/cli/main.py +561 -0
  111. dynamic_systems_testing_framework-1.0.1/src/dstf/cli/review.py +398 -0
  112. dynamic_systems_testing_framework-1.0.1/src/dstf/cli/run_cmds.py +589 -0
  113. dynamic_systems_testing_framework-1.0.1/src/dstf/cli/spec_cmds.py +123 -0
  114. dynamic_systems_testing_framework-1.0.1/src/dstf/comparison/__init__.py +13 -0
  115. dynamic_systems_testing_framework-1.0.1/src/dstf/comparison/algorithms.py +2127 -0
  116. dynamic_systems_testing_framework-1.0.1/src/dstf/comparison/builtins.py +291 -0
  117. dynamic_systems_testing_framework-1.0.1/src/dstf/comparison/comparator.py +1189 -0
  118. dynamic_systems_testing_framework-1.0.1/src/dstf/comparison/geometry.py +164 -0
  119. dynamic_systems_testing_framework-1.0.1/src/dstf/comparison/handles.py +1194 -0
  120. dynamic_systems_testing_framework-1.0.1/src/dstf/comparison/metric_tree.py +332 -0
  121. dynamic_systems_testing_framework-1.0.1/src/dstf/comparison/mode_schema.py +176 -0
  122. dynamic_systems_testing_framework-1.0.1/src/dstf/comparison/modes.py +788 -0
  123. dynamic_systems_testing_framework-1.0.1/src/dstf/comparison/registry.py +230 -0
  124. dynamic_systems_testing_framework-1.0.1/src/dstf/comparison/seeds.py +281 -0
  125. dynamic_systems_testing_framework-1.0.1/src/dstf/comparison/sides.py +158 -0
  126. dynamic_systems_testing_framework-1.0.1/src/dstf/comparison/snap.py +62 -0
  127. dynamic_systems_testing_framework-1.0.1/src/dstf/comparison/strict_keys.py +246 -0
  128. dynamic_systems_testing_framework-1.0.1/src/dstf/comparison/summaries.py +354 -0
  129. dynamic_systems_testing_framework-1.0.1/src/dstf/comparison/tree_eval.py +868 -0
  130. dynamic_systems_testing_framework-1.0.1/src/dstf/comparison/tree_spec.py +678 -0
  131. dynamic_systems_testing_framework-1.0.1/src/dstf/comparison/types.py +194 -0
  132. dynamic_systems_testing_framework-1.0.1/src/dstf/comparison/validator.py +232 -0
  133. dynamic_systems_testing_framework-1.0.1/src/dstf/config.py +815 -0
  134. dynamic_systems_testing_framework-1.0.1/src/dstf/discovery/__init__.py +0 -0
  135. dynamic_systems_testing_framework-1.0.1/src/dstf/discovery/json_recognizer.py +702 -0
  136. dynamic_systems_testing_framework-1.0.1/src/dstf/discovery/library_state.py +248 -0
  137. dynamic_systems_testing_framework-1.0.1/src/dstf/discovery/mo_parser.py +794 -0
  138. dynamic_systems_testing_framework-1.0.1/src/dstf/discovery/patch_apply.py +308 -0
  139. dynamic_systems_testing_framework-1.0.1/src/dstf/discovery/patch_envelope.py +63 -0
  140. dynamic_systems_testing_framework-1.0.1/src/dstf/discovery/plots.py +318 -0
  141. dynamic_systems_testing_framework-1.0.1/src/dstf/discovery/recognizer.py +103 -0
  142. dynamic_systems_testing_framework-1.0.1/src/dstf/discovery/scan_cache.py +154 -0
  143. dynamic_systems_testing_framework-1.0.1/src/dstf/discovery/spec_parser.py +538 -0
  144. dynamic_systems_testing_framework-1.0.1/src/dstf/discovery/spec_shape.py +122 -0
  145. dynamic_systems_testing_framework-1.0.1/src/dstf/discovery/spec_update.py +493 -0
  146. dynamic_systems_testing_framework-1.0.1/src/dstf/discovery/test_registry.py +488 -0
  147. dynamic_systems_testing_framework-1.0.1/src/dstf/discovery/unit_tests.py +95 -0
  148. dynamic_systems_testing_framework-1.0.1/src/dstf/figures/__init__.py +14 -0
  149. dynamic_systems_testing_framework-1.0.1/src/dstf/figures/assemble.py +48 -0
  150. dynamic_systems_testing_framework-1.0.1/src/dstf/figures/decimate.py +150 -0
  151. dynamic_systems_testing_framework-1.0.1/src/dstf/figures/families.py +289 -0
  152. dynamic_systems_testing_framework-1.0.1/src/dstf/figures/palette.py +170 -0
  153. dynamic_systems_testing_framework-1.0.1/src/dstf/figures/plotly.py +1413 -0
  154. dynamic_systems_testing_framework-1.0.1/src/dstf/figures/view.py +233 -0
  155. dynamic_systems_testing_framework-1.0.1/src/dstf/pipeline.py +435 -0
  156. dynamic_systems_testing_framework-1.0.1/src/dstf/plugins.py +104 -0
  157. dynamic_systems_testing_framework-1.0.1/src/dstf/reporting/__init__.py +0 -0
  158. dynamic_systems_testing_framework-1.0.1/src/dstf/reporting/console_report.py +187 -0
  159. dynamic_systems_testing_framework-1.0.1/src/dstf/reporting/context_builder.py +979 -0
  160. dynamic_systems_testing_framework-1.0.1/src/dstf/reporting/dashboard_render.py +534 -0
  161. dynamic_systems_testing_framework-1.0.1/src/dstf/reporting/junit_report.py +192 -0
  162. dynamic_systems_testing_framework-1.0.1/src/dstf/reporting/overlay_loader.py +708 -0
  163. dynamic_systems_testing_framework-1.0.1/src/dstf/reporting/report_suite.py +1059 -0
  164. dynamic_systems_testing_framework-1.0.1/src/dstf/reporting/rows.py +458 -0
  165. dynamic_systems_testing_framework-1.0.1/src/dstf/reporting/schema_export.py +413 -0
  166. dynamic_systems_testing_framework-1.0.1/src/dstf/reporting/stats_rows.py +321 -0
  167. dynamic_systems_testing_framework-1.0.1/src/dstf/reporting/status.py +388 -0
  168. dynamic_systems_testing_framework-1.0.1/src/dstf/reporting/templates/axes.js +61 -0
  169. dynamic_systems_testing_framework-1.0.1/src/dstf/reporting/templates/dashboard.html +284 -0
  170. dynamic_systems_testing_framework-1.0.1/src/dstf/reporting/templates/dashboard.js +604 -0
  171. dynamic_systems_testing_framework-1.0.1/src/dstf/reporting/templates/filters.js +100 -0
  172. dynamic_systems_testing_framework-1.0.1/src/dstf/reporting/templates/interactive.html +420 -0
  173. dynamic_systems_testing_framework-1.0.1/src/dstf/reporting/templates/report.js +116 -0
  174. dynamic_systems_testing_framework-1.0.1/src/dstf/reporting/templates/vendor/plotly.min.js +8 -0
  175. dynamic_systems_testing_framework-1.0.1/src/dstf/reporting/theme.py +324 -0
  176. dynamic_systems_testing_framework-1.0.1/src/dstf/reporting/tree_rows.py +73 -0
  177. dynamic_systems_testing_framework-1.0.1/src/dstf/reporting/verdicts.py +124 -0
  178. dynamic_systems_testing_framework-1.0.1/src/dstf/storage/__init__.py +0 -0
  179. dynamic_systems_testing_framework-1.0.1/src/dstf/storage/accept.py +216 -0
  180. dynamic_systems_testing_framework-1.0.1/src/dstf/storage/baseline.py +43 -0
  181. dynamic_systems_testing_framework-1.0.1/src/dstf/storage/batch_manifest.py +204 -0
  182. dynamic_systems_testing_framework-1.0.1/src/dstf/storage/ref_index.py +295 -0
  183. dynamic_systems_testing_framework-1.0.1/src/dstf/storage/reference_store.py +661 -0
  184. dynamic_systems_testing_framework-1.0.1/src/dstf/storage/roles.py +576 -0
  185. dynamic_systems_testing_framework-1.0.1/src/dstf/storage/run_stats.py +85 -0
@@ -0,0 +1,89 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[codz]
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ *.egg
8
+
9
+ # Virtual environments
10
+ .venv/
11
+ venv/
12
+ .env
13
+
14
+ # uv
15
+ # uv.lock is committed for reproducibility
16
+
17
+ # Dymola artifacts
18
+ *.mat
19
+ dslog.txt
20
+ dsin.txt
21
+ dsfinal.txt
22
+ buildlog.txt
23
+ dymosim
24
+ dymosim.exe
25
+ dymosim.exp
26
+ dymosim.lib
27
+ dymosim.dll
28
+ dsmodel.c
29
+ dsmodel_att.h
30
+ dymola.log
31
+ status
32
+ success
33
+ failure
34
+ *.bif-*
35
+
36
+ # Keep test fixture results (override above exclusions)
37
+ !tests/fixtures/results/**/*.mat
38
+ !tests/fixtures/results/**/dslog.txt
39
+ !tests/fixtures/results/**/dsin.txt
40
+ !tests/fixtures/results/**/dsfinal.txt
41
+ !tests/fixtures/results_openmodelica/**/*.mat
42
+
43
+ # Simulation output (generated by the tool)
44
+ testing_output/
45
+
46
+ # Generated reports (dashboard.html, interactive plots, comparison_data.json)
47
+ reports/
48
+
49
+ # Reference-FMUs binaries (fetched by scripts/fetch_reference_fmus.py)
50
+ examples/fmu/reference-fmus-binaries/
51
+
52
+ # IDE
53
+ .idea/
54
+ .vscode/
55
+ *.swp
56
+ *.swo
57
+
58
+ # OS
59
+ .DS_Store
60
+ Thumbs.db
61
+
62
+ # Coverage / testing
63
+ .coverage
64
+ .coverage.*
65
+ htmlcov/
66
+ .pytest_cache/
67
+ .tox/
68
+ .nox/
69
+
70
+ # Translations (gettext .mo — NOT Modelica .mo files)
71
+ *.pot
72
+
73
+ # Cursor
74
+ .cursorignore
75
+ .cursorindexingignore
76
+ # Local agent configuration and working notes. Machine-local: the paths
77
+ # inside resolve only on the machine that wrote them.
78
+ .claude/
79
+
80
+ # Test fixtures named like Dymola artifacts are real, committed test data —
81
+ # the artifact patterns above (dslog.txt, *.mat, ...) must not swallow them.
82
+ # (results/Dymola/dslog.txt + dsres.mat were already force-added; this keeps
83
+ # the results_additional/ dslog fixture tracked too. Big generated fixtures —
84
+ # dsfinal.txt, dsin.txt, dsmodel.c — stay ignored: no test references them.)
85
+ !tests/fixtures/**/dslog.txt
86
+
87
+ # Local working-session notes and agent state — never published.
88
+ # The project's durable record is docs/decisions.md and docs/ideas.md.
89
+ .soul/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ORNL-Modelica
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,266 @@
1
+ Metadata-Version: 2.5
2
+ Name: dynamic-systems-testing-framework
3
+ Version: 1.0.1
4
+ Summary: Dynamic Systems Testing Framework — regression & unit testing for time-dependent system behavior across Modelica (Dymola, OpenModelica), FMU (FMPy), Julia (ModelingToolkit), and Python backends
5
+ Project-URL: Homepage, https://github.com/ORNL-Modelica/DynamicSystemsTestingFramework
6
+ Project-URL: Repository, https://github.com/ORNL-Modelica/DynamicSystemsTestingFramework
7
+ Project-URL: Documentation, https://github.com/ORNL-Modelica/DynamicSystemsTestingFramework/blob/main/docs/usage.md
8
+ Project-URL: Issues, https://github.com/ORNL-Modelica/DynamicSystemsTestingFramework/issues
9
+ Author: Scott Greenwood
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: dymola,fmi,fmu,julia,modelica,modelingtoolkit,openmodelica,regression-testing,simulation,testing
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Topic :: Scientific/Engineering
19
+ Classifier: Topic :: Software Development :: Testing
20
+ Requires-Python: >=3.10
21
+ Requires-Dist: jinja2>=3.1
22
+ Requires-Dist: numpy>=1.20
23
+ Requires-Dist: psutil>=5.9
24
+ Provides-Extra: author
25
+ Requires-Dist: nicegui>=3.16; extra == 'author'
26
+ Requires-Dist: regex>=2026.9.10; extra == 'author'
27
+ Provides-Extra: dev
28
+ Requires-Dist: mypy>=1.10; extra == 'dev'
29
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
30
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
31
+ Requires-Dist: pytest>=7.0; extra == 'dev'
32
+ Requires-Dist: ruff>=0.16; extra == 'dev'
33
+ Requires-Dist: scipy>=1.10; extra == 'dev'
34
+ Requires-Dist: types-regex>=2026.9.10; extra == 'dev'
35
+ Provides-Extra: fmpy
36
+ Requires-Dist: fmpy>=0.3; extra == 'fmpy'
37
+ Provides-Extra: om
38
+ Requires-Dist: ompython>=3.5; extra == 'om'
39
+ Description-Content-Type: text/markdown
40
+
41
+ # Dynamic Systems Testing Framework (DSTF)
42
+
43
+ [![quality](https://github.com/ORNL-Modelica/DynamicSystemsTestingFramework/actions/workflows/quality.yml/badge.svg)](https://github.com/ORNL-Modelica/DynamicSystemsTestingFramework/actions/workflows/quality.yml)
44
+
45
+ Regression and unit testing for time-dependent system behavior. Discovers tests, runs simulations, compares against versioned baselines, and reports — across **Modelica (Dymola, OpenModelica), FMU (FMPy), Julia/ModelingToolkit, and arbitrary Python**.
46
+
47
+ Library-agnostic: tests can be discovered from in-model annotations (`UnitTests` components), declarative `test_spec.json`, or both. Reference results are partitioned per backend / OS so the same library can be regression-tested across backends without ref drift.
48
+
49
+ Criteria are written in **`dstf author`**, a local browser tool over the same figures the report draws: edit a criterion beside the plot it scores — drag a handle, or Ctrl+click to add a row that settles on the data — give a tolerance a lower and an upper side, put one criterion on many elements of an array, queue tests on simulator workers that stay alive, and watch a running test's trace as Dymola or OpenModelica writes it. A default and a dark theme cover the tool, the dashboard and the report pages.
50
+
51
+ ![DSTF dashboard](https://raw.githubusercontent.com/ORNL-Modelica/DynamicSystemsTestingFramework/main/docs/img/dashboard.png)
52
+
53
+ *The unified dashboard — live progress during a run, a static report after. Each report is stamped with the backend, tool + MSL version, and OS that produced it; the table gives per-test verdicts, worst-NRMSE, and phase timing.*
54
+
55
+ ## What's in the box
56
+
57
+ - **5 backends**, each with persistent-worker support where it pays off:
58
+
59
+ | Backend | Source kind | Persistent | Notes |
60
+ |---|---|---|---|
61
+ | Dymola | Modelica `.mo` | ✓ default | Python interface; `--batch` selects the `.mos` path. Records translation statistics, so a change in a model's state count is a structural warning |
62
+ | OpenModelica | Modelica `.mo` | ✓ default | OMPython ZMQ; `--batch` selects the `omc -s` path. Records timing statistics and the model's state count (from the init file omc generates), so a change in it is the structural warning it is on Dymola — against a baseline that records the count, which one accepted before this does at its next accept; system sizes and Jacobian counts are Dymola's alone |
63
+ | FMPy | Pre-built FMU | per-test thread | `fmpy.simulate_fmu` in-process |
64
+ | Julia / MTK | `.jl` ModelingToolkit | ✓ default | stdin-JSON pipe; Dyad untested |
65
+ | Python | Any `simulate(stop_time, tol) -> dict` | subprocess-per-test | scipy, pandas, CSV loader, HTTP — anything |
66
+
67
+ - **7 comparison modes**, composable via a `MetricTree`:
68
+
69
+ | Mode | What it scores |
70
+ |---|---|
71
+ | `nrmse` | RMSE over signal range — the default |
72
+ | `tube` | Pass if signal stays inside a (constant or time-varying) envelope around ref |
73
+ | `points` | Per-point checks at declared times with `time_tolerance` x-box and abs/rel y-tolerance |
74
+ | `range` | Scalar `min_value` / `max_value` bounds — baseline-free |
75
+ | `event-timing` | Match Modelica solver events against a declared list within per-event tolerance |
76
+ | `dominant-frequency` | FFT peak matching against a declared peaks table — windowable |
77
+ | `scalar` | One number — a reduction of the signal (`max`/`min`/`mean`/`sample_mean`/`final`/`integral`) or a stored statistic by dotted path — vs a baseline scalar or declared bounds |
78
+
79
+ Combinators: `and`, `or`, `k-of-n`, `warn` (relax to advisory), `weighted`. Leaves can scope to a time window and target named baselines (`primary`, soft-checks, companions).
80
+
81
+ - **Read-only reports** — per-test Plotly HTML drawn from figures Python built: the trajectory with its criterion geometry (tube band, range bounds, point boxes, event windows, FFT spectrum), overlay picker, error overlays, and the metric tree with the CLI's verdict and score text per leaf. Plus a live dashboard during runs and JUnit XML for CI. The report shows, the CLI decides.
82
+
83
+ - **An authoring tool** — `dstf author` (the `[author]` extra) serves a Suite page and a Test page on `127.0.0.1`. Criteria are edited inline under the plot they score, staged, and written to `test_spec.json` on Save:
84
+
85
+ | Feature | What it does |
86
+ |---|---|
87
+ | Two-sided tolerance | A tolerance is one number or `{"lower": a, "upper": b}`; on the plot, an arrow outside each side sets it |
88
+ | On-plot editing | Drag a ring, an arrow or a bound line; Ctrl+click adds a row that settles on the data; a field's ⌖ arms it for the next click; a placed value is snapped to a readable step |
89
+ | Simulation queue | Queue the selected tests: first in, first out, on workers that stay alive between runs; Remove a waiting test, Cancel a running one |
90
+ | Live results | A running test's trace is drawn as Dymola or OpenModelica writes its result file; a cancelled or timed-out run is shown, never scored or accepted |
91
+ | Criteria over an array | One criterion on the elements `1:5:20` of an array; identical criteria fold into one row, edited as one |
92
+ | Themes | `"theme": "dark"` in `testing.json` for the dashboard, the report pages and the tool; the tool's ⋮ menu switches a browser tab live |
93
+
94
+ - **Three baseline roles** per test, partitioned on disk: **primary** (regression anchor, hard-fail), **soft_checks** (warn-wrapped cross-regression imports), **companions** (plot-only overlays, including cross-library).
95
+
96
+ ## Install
97
+
98
+ End users:
99
+
100
+ ```bash
101
+ # Not on PyPI yet — these work from the first published release.
102
+ uv tool install dynamic-systems-testing-framework # then run plain: dstf ...
103
+ # or: pipx install dynamic-systems-testing-framework
104
+ ```
105
+
106
+ Developers:
107
+
108
+ ```bash
109
+ uv sync --extra dev --locked # core + pytest, from uv.lock
110
+ uv sync --extra dev --extra author --extra fmpy --extra om --locked # plus the authoring tool, FMPy + OpenModelica extras
111
+ uv run dstf --help
112
+ ```
113
+
114
+ `uv sync` installs the project editable and pins every dependency to `uv.lock`,
115
+ the same lock CI uses; `--locked` fails instead of silently re-locking when the
116
+ lock has drifted from `pyproject.toml`. It prunes anything you did not ask for
117
+ on that command line — being in the lock does not save it — so name every extra
118
+ at once.
119
+
120
+ For the Julia backend, install Julia 1.11+ and instantiate the demo project once:
121
+
122
+ ```bash
123
+ curl -fsSL https://install.julialang.org | sh -s -- -y --default-channel 1.11
124
+ cd examples/julia/JuliaMtkTestingLib && julia --project=. -e 'using Pkg; Pkg.instantiate()'
125
+ ```
126
+
127
+ The Python examples (`SimpleRamp`, `PointsCheck`) need scipy, which the `dev`
128
+ extra installs. Reach them through `uv run dstf ...`: the Python backend takes
129
+ the interpreter from `testing.json`'s `backends: {"Python": [...]}` entry and
130
+ falls back to `PATH` — and the shipped example names `python`, so either route
131
+ ends at the first `python` on `PATH`, which `uv run` points at `.venv`. Run the
132
+ same examples from a tool-installed `dstf` and that is whatever comes first on
133
+ your PATH — a conda env, often — which needs its own scipy.
134
+
135
+ ## First 5 minutes
136
+
137
+ The repo ships demo libraries for every backend. Easiest first run is the Modelica demo:
138
+
139
+ ```bash
140
+ # From the repo root:
141
+ uv run dstf --config examples/modelica/ModelicaTestingLib/Resources/ReferenceResults/testing.json run
142
+ ```
143
+
144
+ What this does:
145
+
146
+ 1. Reads `testing.json` to find the demo library, the backend (Dymola or OpenModelica — first one whose binary exists wins), the reference root, and any per-test recognizers.
147
+ 2. Discovers the demo tests via the bundled `UnitTests` recognizer plus declarative recognizers in the JSON.
148
+ 3. Runs each in a persistent simulator worker, partitioning output under `testing_output/` by backend + OS.
149
+ 4. Compares against `Resources/ReferenceResults/<Backend>/<os>/ref_NNNN.json` baselines.
150
+ 5. Prints a console report with pass/fail per test.
151
+
152
+ To see the interactive HTML reporter:
153
+
154
+ ```bash
155
+ uv run dstf --config examples/modelica/ModelicaTestingLib/Resources/ReferenceResults/testing.json run --report
156
+ ```
157
+
158
+ The dashboard URL is printed as a run starts (`Live progress: file://…`) and the page is opened in a browser tab; it reloads itself every 5s during the run. `--report` writes the per-test pages under `<work_dir>/reports/` and opens the dashboard again when they are written. `--no-browser` (on `run` and `compare`) opens no tab and still prints the link.
159
+
160
+ The examples ship baselines for these `<Backend>/<os>` partitions: Modelica — `Dymola/linux`, `Dymola/windows` and `OpenModelica/linux` (its array model, `HeatRodTest`, on the two Linux ones); FMU — `FMPy/linux` and `FMPy/windows`; Julia — `Julia/linux`; Python — `Python/linux`. A first run on an OS a backend has no partition for (OpenModelica, Julia or Python on Windows, say) reports every test `NO_REF` until `run --accept` stores its baselines there. A companion in the examples is another source's curve of the SAME model, drawn over the test's plot when its box is ticked on the report page, and each ships in the partitions named here and no other: in `OpenModelica/linux`, the Modelica `FrequencyTest`, `RangeCheckTest` and `MultiFrequencyTest` carry the Julia example's baseline of that model; in `Julia/linux`, the Julia `Frequency`, `RangeCheck` and `MultiFrequency` carry the OpenModelica one; and `MetricTreeTest` carries its closed-form solution in `Dymola/linux` and `OpenModelica/linux`. A Dymola run of the example therefore shows no Julia companion, and `Dymola/windows` ships no companion at all.
161
+
162
+ To repeat with another backend's demo library, swap the config path:
163
+
164
+ ```bash
165
+ # Julia/MTK, Python, and prebuilt FMUs through FMPy
166
+ uv run dstf --config examples/julia/JuliaMtkTestingLib/Resources/ReferenceResults/testing.json run
167
+ uv run dstf --config examples/python/PythonTestingLib/Resources/ReferenceResults/testing.json run
168
+ uv run dstf --config examples/fmu/testing.json run # needs reference-fmus-binaries/
169
+ ```
170
+
171
+ ## Configuration cheat-sheet
172
+
173
+ `testing.json` is the single entry point. The full field reference lives in `docs/usage.md`; the headline shape:
174
+
175
+ ```json
176
+ {
177
+ "source_path": "../../MyLib",
178
+ "backends": {
179
+ "Dymola": ["C:\\Program Files\\Dymola 2026x\\bin64\\Dymola.exe"],
180
+ "OpenModelica": ["/usr/bin/omc"]
181
+ },
182
+ "test_spec": "test_spec.json",
183
+ "dependencies": ["/path/to/SomeDep"],
184
+ "tolerance": 1e-4,
185
+ "diagnostic_variables": ["CPUtime", "EventCounter"]
186
+ }
187
+ ```
188
+
189
+ The first `backends` entry whose binary exists wins (no need for per-OS config files). `backend: "Dymola"` (or any named entry) forces a specific one.
190
+
191
+ ## Common commands
192
+
193
+ ```bash
194
+ # Discover tests without running
195
+ uv run dstf --config testing.json discover
196
+
197
+ # Run, compare, accept all current results as new baselines
198
+ uv run dstf --config testing.json run --accept
199
+
200
+ # Interactive review by category
201
+ uv run dstf --config testing.json run -i failed
202
+
203
+ # Filter (glob, comma list, or @file)
204
+ uv run dstf --config testing.json run --filter "Foo.A,Foo.B"
205
+ uv run dstf --config testing.json run --filter @rerun.txt
206
+
207
+ # Parallel + interactive HTML report (--batch-size N splits a Dymola --batch run into small batches)
208
+ uv run dstf --config testing.json run --parallel 4 --report
209
+
210
+ # Rerun only previously-failed tests, merge with last full run, regen report
211
+ uv run dstf --config testing.json run --rerun failed,sim-failed --merge --report
212
+
213
+ # Compare without re-simulating (uses last results)
214
+ uv run dstf --config testing.json compare
215
+
216
+ # Open the authoring tool in a browser (needs the [author] extra)
217
+ uv run dstf --config testing.json author
218
+
219
+ # Apply an RFC 6902 JSON-Patch envelope against test_spec.json — single- or
220
+ # multi-model form, from any source
221
+ uv run dstf --config testing.json spec-update spec_patch.json
222
+
223
+ # Manage the other baseline roles
224
+ uv run dstf --config testing.json companion add <model> <name> <path>
225
+ uv run dstf --config testing.json soft-check list <model>
226
+ uv run dstf --config testing.json import-baseline <model> <name> <source> # soft_checks only
227
+
228
+ # Manifest / schema
229
+ uv run dstf --config testing.json manifest dump
230
+ uv run dstf --config testing.json manifest cleanup [--orphans] [--apply] # dry-run by default
231
+ uv run dstf --config testing.json export-schema --output schema.json
232
+
233
+ # Diagnose Dymola Python interface discovery
234
+ uv run dstf check-dymola
235
+ ```
236
+
237
+ `uv run dstf <command> --help` for each subcommand's full flag set.
238
+
239
+ ## Where things live
240
+
241
+ | Doc | What's in it |
242
+ |---|---|
243
+ | `docs/usage.md` | The deep user guide — every command, every config field, every comparison mode |
244
+ | `docs/architecture.md` | Six-layer plug-in pipeline + current-state map to code |
245
+ | `docs/extensibility.md` | Plug-in contracts for Source / Discovery / Backend / Dataset / Metric / Combinator |
246
+ | `docs/vision.md` | Where the framework is going (target user base, non-Modelica futures) |
247
+ | `docs/decisions.md` | Authoritative decision log |
248
+ | `docs/ideas.md` | Backlog (unimplemented features, with explicit deferred-by-design entries) |
249
+ | `examples/{modelica,fmu,julia,python}/` | Working demo libraries — one per backend |
250
+
251
+ ## CI integration
252
+
253
+ ```yaml
254
+ - run: |
255
+ uv run dstf --config ./testing.json run --report-format junit --output test-results.xml
256
+ - uses: actions/upload-artifact@v4
257
+ with:
258
+ name: test-results
259
+ path: test-results.xml
260
+ ```
261
+
262
+ For HTML reports as build artifacts, also pass `--report` and upload `dashboard.html` and the `reports/` directory from the work dir (`--work-dir` sets it).
263
+
264
+ ## Status
265
+
266
+ v1.0. 5 backends in production, 4 demo libraries, and a comprehensive pytest suite (a Playwright subset drives the report pages and the authoring tool in a real browser). The report is read-only and mutates nothing: every number it draws comes from a figure Python built or a string the server rendered. Criteria are authored in `dstf author`, driven by the same figures and the same scorer as the CLI. Nothing is published to PyPI yet.
@@ -0,0 +1,226 @@
1
+ # Dynamic Systems Testing Framework (DSTF)
2
+
3
+ [![quality](https://github.com/ORNL-Modelica/DynamicSystemsTestingFramework/actions/workflows/quality.yml/badge.svg)](https://github.com/ORNL-Modelica/DynamicSystemsTestingFramework/actions/workflows/quality.yml)
4
+
5
+ Regression and unit testing for time-dependent system behavior. Discovers tests, runs simulations, compares against versioned baselines, and reports — across **Modelica (Dymola, OpenModelica), FMU (FMPy), Julia/ModelingToolkit, and arbitrary Python**.
6
+
7
+ Library-agnostic: tests can be discovered from in-model annotations (`UnitTests` components), declarative `test_spec.json`, or both. Reference results are partitioned per backend / OS so the same library can be regression-tested across backends without ref drift.
8
+
9
+ Criteria are written in **`dstf author`**, a local browser tool over the same figures the report draws: edit a criterion beside the plot it scores — drag a handle, or Ctrl+click to add a row that settles on the data — give a tolerance a lower and an upper side, put one criterion on many elements of an array, queue tests on simulator workers that stay alive, and watch a running test's trace as Dymola or OpenModelica writes it. A default and a dark theme cover the tool, the dashboard and the report pages.
10
+
11
+ ![DSTF dashboard](https://raw.githubusercontent.com/ORNL-Modelica/DynamicSystemsTestingFramework/main/docs/img/dashboard.png)
12
+
13
+ *The unified dashboard — live progress during a run, a static report after. Each report is stamped with the backend, tool + MSL version, and OS that produced it; the table gives per-test verdicts, worst-NRMSE, and phase timing.*
14
+
15
+ ## What's in the box
16
+
17
+ - **5 backends**, each with persistent-worker support where it pays off:
18
+
19
+ | Backend | Source kind | Persistent | Notes |
20
+ |---|---|---|---|
21
+ | Dymola | Modelica `.mo` | ✓ default | Python interface; `--batch` selects the `.mos` path. Records translation statistics, so a change in a model's state count is a structural warning |
22
+ | OpenModelica | Modelica `.mo` | ✓ default | OMPython ZMQ; `--batch` selects the `omc -s` path. Records timing statistics and the model's state count (from the init file omc generates), so a change in it is the structural warning it is on Dymola — against a baseline that records the count, which one accepted before this does at its next accept; system sizes and Jacobian counts are Dymola's alone |
23
+ | FMPy | Pre-built FMU | per-test thread | `fmpy.simulate_fmu` in-process |
24
+ | Julia / MTK | `.jl` ModelingToolkit | ✓ default | stdin-JSON pipe; Dyad untested |
25
+ | Python | Any `simulate(stop_time, tol) -> dict` | subprocess-per-test | scipy, pandas, CSV loader, HTTP — anything |
26
+
27
+ - **7 comparison modes**, composable via a `MetricTree`:
28
+
29
+ | Mode | What it scores |
30
+ |---|---|
31
+ | `nrmse` | RMSE over signal range — the default |
32
+ | `tube` | Pass if signal stays inside a (constant or time-varying) envelope around ref |
33
+ | `points` | Per-point checks at declared times with `time_tolerance` x-box and abs/rel y-tolerance |
34
+ | `range` | Scalar `min_value` / `max_value` bounds — baseline-free |
35
+ | `event-timing` | Match Modelica solver events against a declared list within per-event tolerance |
36
+ | `dominant-frequency` | FFT peak matching against a declared peaks table — windowable |
37
+ | `scalar` | One number — a reduction of the signal (`max`/`min`/`mean`/`sample_mean`/`final`/`integral`) or a stored statistic by dotted path — vs a baseline scalar or declared bounds |
38
+
39
+ Combinators: `and`, `or`, `k-of-n`, `warn` (relax to advisory), `weighted`. Leaves can scope to a time window and target named baselines (`primary`, soft-checks, companions).
40
+
41
+ - **Read-only reports** — per-test Plotly HTML drawn from figures Python built: the trajectory with its criterion geometry (tube band, range bounds, point boxes, event windows, FFT spectrum), overlay picker, error overlays, and the metric tree with the CLI's verdict and score text per leaf. Plus a live dashboard during runs and JUnit XML for CI. The report shows, the CLI decides.
42
+
43
+ - **An authoring tool** — `dstf author` (the `[author]` extra) serves a Suite page and a Test page on `127.0.0.1`. Criteria are edited inline under the plot they score, staged, and written to `test_spec.json` on Save:
44
+
45
+ | Feature | What it does |
46
+ |---|---|
47
+ | Two-sided tolerance | A tolerance is one number or `{"lower": a, "upper": b}`; on the plot, an arrow outside each side sets it |
48
+ | On-plot editing | Drag a ring, an arrow or a bound line; Ctrl+click adds a row that settles on the data; a field's ⌖ arms it for the next click; a placed value is snapped to a readable step |
49
+ | Simulation queue | Queue the selected tests: first in, first out, on workers that stay alive between runs; Remove a waiting test, Cancel a running one |
50
+ | Live results | A running test's trace is drawn as Dymola or OpenModelica writes its result file; a cancelled or timed-out run is shown, never scored or accepted |
51
+ | Criteria over an array | One criterion on the elements `1:5:20` of an array; identical criteria fold into one row, edited as one |
52
+ | Themes | `"theme": "dark"` in `testing.json` for the dashboard, the report pages and the tool; the tool's ⋮ menu switches a browser tab live |
53
+
54
+ - **Three baseline roles** per test, partitioned on disk: **primary** (regression anchor, hard-fail), **soft_checks** (warn-wrapped cross-regression imports), **companions** (plot-only overlays, including cross-library).
55
+
56
+ ## Install
57
+
58
+ End users:
59
+
60
+ ```bash
61
+ # Not on PyPI yet — these work from the first published release.
62
+ uv tool install dynamic-systems-testing-framework # then run plain: dstf ...
63
+ # or: pipx install dynamic-systems-testing-framework
64
+ ```
65
+
66
+ Developers:
67
+
68
+ ```bash
69
+ uv sync --extra dev --locked # core + pytest, from uv.lock
70
+ uv sync --extra dev --extra author --extra fmpy --extra om --locked # plus the authoring tool, FMPy + OpenModelica extras
71
+ uv run dstf --help
72
+ ```
73
+
74
+ `uv sync` installs the project editable and pins every dependency to `uv.lock`,
75
+ the same lock CI uses; `--locked` fails instead of silently re-locking when the
76
+ lock has drifted from `pyproject.toml`. It prunes anything you did not ask for
77
+ on that command line — being in the lock does not save it — so name every extra
78
+ at once.
79
+
80
+ For the Julia backend, install Julia 1.11+ and instantiate the demo project once:
81
+
82
+ ```bash
83
+ curl -fsSL https://install.julialang.org | sh -s -- -y --default-channel 1.11
84
+ cd examples/julia/JuliaMtkTestingLib && julia --project=. -e 'using Pkg; Pkg.instantiate()'
85
+ ```
86
+
87
+ The Python examples (`SimpleRamp`, `PointsCheck`) need scipy, which the `dev`
88
+ extra installs. Reach them through `uv run dstf ...`: the Python backend takes
89
+ the interpreter from `testing.json`'s `backends: {"Python": [...]}` entry and
90
+ falls back to `PATH` — and the shipped example names `python`, so either route
91
+ ends at the first `python` on `PATH`, which `uv run` points at `.venv`. Run the
92
+ same examples from a tool-installed `dstf` and that is whatever comes first on
93
+ your PATH — a conda env, often — which needs its own scipy.
94
+
95
+ ## First 5 minutes
96
+
97
+ The repo ships demo libraries for every backend. Easiest first run is the Modelica demo:
98
+
99
+ ```bash
100
+ # From the repo root:
101
+ uv run dstf --config examples/modelica/ModelicaTestingLib/Resources/ReferenceResults/testing.json run
102
+ ```
103
+
104
+ What this does:
105
+
106
+ 1. Reads `testing.json` to find the demo library, the backend (Dymola or OpenModelica — first one whose binary exists wins), the reference root, and any per-test recognizers.
107
+ 2. Discovers the demo tests via the bundled `UnitTests` recognizer plus declarative recognizers in the JSON.
108
+ 3. Runs each in a persistent simulator worker, partitioning output under `testing_output/` by backend + OS.
109
+ 4. Compares against `Resources/ReferenceResults/<Backend>/<os>/ref_NNNN.json` baselines.
110
+ 5. Prints a console report with pass/fail per test.
111
+
112
+ To see the interactive HTML reporter:
113
+
114
+ ```bash
115
+ uv run dstf --config examples/modelica/ModelicaTestingLib/Resources/ReferenceResults/testing.json run --report
116
+ ```
117
+
118
+ The dashboard URL is printed as a run starts (`Live progress: file://…`) and the page is opened in a browser tab; it reloads itself every 5s during the run. `--report` writes the per-test pages under `<work_dir>/reports/` and opens the dashboard again when they are written. `--no-browser` (on `run` and `compare`) opens no tab and still prints the link.
119
+
120
+ The examples ship baselines for these `<Backend>/<os>` partitions: Modelica — `Dymola/linux`, `Dymola/windows` and `OpenModelica/linux` (its array model, `HeatRodTest`, on the two Linux ones); FMU — `FMPy/linux` and `FMPy/windows`; Julia — `Julia/linux`; Python — `Python/linux`. A first run on an OS a backend has no partition for (OpenModelica, Julia or Python on Windows, say) reports every test `NO_REF` until `run --accept` stores its baselines there. A companion in the examples is another source's curve of the SAME model, drawn over the test's plot when its box is ticked on the report page, and each ships in the partitions named here and no other: in `OpenModelica/linux`, the Modelica `FrequencyTest`, `RangeCheckTest` and `MultiFrequencyTest` carry the Julia example's baseline of that model; in `Julia/linux`, the Julia `Frequency`, `RangeCheck` and `MultiFrequency` carry the OpenModelica one; and `MetricTreeTest` carries its closed-form solution in `Dymola/linux` and `OpenModelica/linux`. A Dymola run of the example therefore shows no Julia companion, and `Dymola/windows` ships no companion at all.
121
+
122
+ To repeat with another backend's demo library, swap the config path:
123
+
124
+ ```bash
125
+ # Julia/MTK, Python, and prebuilt FMUs through FMPy
126
+ uv run dstf --config examples/julia/JuliaMtkTestingLib/Resources/ReferenceResults/testing.json run
127
+ uv run dstf --config examples/python/PythonTestingLib/Resources/ReferenceResults/testing.json run
128
+ uv run dstf --config examples/fmu/testing.json run # needs reference-fmus-binaries/
129
+ ```
130
+
131
+ ## Configuration cheat-sheet
132
+
133
+ `testing.json` is the single entry point. The full field reference lives in `docs/usage.md`; the headline shape:
134
+
135
+ ```json
136
+ {
137
+ "source_path": "../../MyLib",
138
+ "backends": {
139
+ "Dymola": ["C:\\Program Files\\Dymola 2026x\\bin64\\Dymola.exe"],
140
+ "OpenModelica": ["/usr/bin/omc"]
141
+ },
142
+ "test_spec": "test_spec.json",
143
+ "dependencies": ["/path/to/SomeDep"],
144
+ "tolerance": 1e-4,
145
+ "diagnostic_variables": ["CPUtime", "EventCounter"]
146
+ }
147
+ ```
148
+
149
+ The first `backends` entry whose binary exists wins (no need for per-OS config files). `backend: "Dymola"` (or any named entry) forces a specific one.
150
+
151
+ ## Common commands
152
+
153
+ ```bash
154
+ # Discover tests without running
155
+ uv run dstf --config testing.json discover
156
+
157
+ # Run, compare, accept all current results as new baselines
158
+ uv run dstf --config testing.json run --accept
159
+
160
+ # Interactive review by category
161
+ uv run dstf --config testing.json run -i failed
162
+
163
+ # Filter (glob, comma list, or @file)
164
+ uv run dstf --config testing.json run --filter "Foo.A,Foo.B"
165
+ uv run dstf --config testing.json run --filter @rerun.txt
166
+
167
+ # Parallel + interactive HTML report (--batch-size N splits a Dymola --batch run into small batches)
168
+ uv run dstf --config testing.json run --parallel 4 --report
169
+
170
+ # Rerun only previously-failed tests, merge with last full run, regen report
171
+ uv run dstf --config testing.json run --rerun failed,sim-failed --merge --report
172
+
173
+ # Compare without re-simulating (uses last results)
174
+ uv run dstf --config testing.json compare
175
+
176
+ # Open the authoring tool in a browser (needs the [author] extra)
177
+ uv run dstf --config testing.json author
178
+
179
+ # Apply an RFC 6902 JSON-Patch envelope against test_spec.json — single- or
180
+ # multi-model form, from any source
181
+ uv run dstf --config testing.json spec-update spec_patch.json
182
+
183
+ # Manage the other baseline roles
184
+ uv run dstf --config testing.json companion add <model> <name> <path>
185
+ uv run dstf --config testing.json soft-check list <model>
186
+ uv run dstf --config testing.json import-baseline <model> <name> <source> # soft_checks only
187
+
188
+ # Manifest / schema
189
+ uv run dstf --config testing.json manifest dump
190
+ uv run dstf --config testing.json manifest cleanup [--orphans] [--apply] # dry-run by default
191
+ uv run dstf --config testing.json export-schema --output schema.json
192
+
193
+ # Diagnose Dymola Python interface discovery
194
+ uv run dstf check-dymola
195
+ ```
196
+
197
+ `uv run dstf <command> --help` for each subcommand's full flag set.
198
+
199
+ ## Where things live
200
+
201
+ | Doc | What's in it |
202
+ |---|---|
203
+ | `docs/usage.md` | The deep user guide — every command, every config field, every comparison mode |
204
+ | `docs/architecture.md` | Six-layer plug-in pipeline + current-state map to code |
205
+ | `docs/extensibility.md` | Plug-in contracts for Source / Discovery / Backend / Dataset / Metric / Combinator |
206
+ | `docs/vision.md` | Where the framework is going (target user base, non-Modelica futures) |
207
+ | `docs/decisions.md` | Authoritative decision log |
208
+ | `docs/ideas.md` | Backlog (unimplemented features, with explicit deferred-by-design entries) |
209
+ | `examples/{modelica,fmu,julia,python}/` | Working demo libraries — one per backend |
210
+
211
+ ## CI integration
212
+
213
+ ```yaml
214
+ - run: |
215
+ uv run dstf --config ./testing.json run --report-format junit --output test-results.xml
216
+ - uses: actions/upload-artifact@v4
217
+ with:
218
+ name: test-results
219
+ path: test-results.xml
220
+ ```
221
+
222
+ For HTML reports as build artifacts, also pass `--report` and upload `dashboard.html` and the `reports/` directory from the work dir (`--work-dir` sets it).
223
+
224
+ ## Status
225
+
226
+ v1.0. 5 backends in production, 4 demo libraries, and a comprehensive pytest suite (a Playwright subset drives the report pages and the authoring tool in a real browser). The report is read-only and mutates nothing: every number it draws comes from a figure Python built or a string the server rendered. Criteria are authored in `dstf author`, driven by the same figures and the same scorer as the CLI. Nothing is published to PyPI yet.