Skip to content

Commit 7464f33

Browse files
committed
feat(core): implement real-time simulation pacing
1 parent 9df10b1 commit 7464f33

4 files changed

Lines changed: 410 additions & 232 deletions

File tree

packages/cli/src/commands/simulate.ts

Lines changed: 54 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ interface SimulateArgs {
1818
interval?: number;
1919
format: string;
2020
solver: string;
21+
realtime?: number;
2122
}
2223

2324
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
@@ -65,10 +66,14 @@ export const Simulate: CommandModule<{}, SimulateArgs> = {
6566
type: "string",
6667
choices: ["rk4", "dopri5", "bdf", "auto"],
6768
default: "dopri5",
69+
})
70+
.option("realtime", {
71+
description: "run simulation in real-time mode with given scale factor (e.g., 1.0 for 1x)",
72+
type: "number",
6873
});
6974
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
7075
}) as CommandModule<{}, SimulateArgs>["builder"],
71-
handler: (args) => {
76+
handler: async (args) => {
7277
const parser = new Parser();
7378
parser.setLanguage(Modelica);
7479
Context.registerParser(".mo", parser);
@@ -161,28 +166,56 @@ export const Simulate: CommandModule<{}, SimulateArgs> = {
161166
const step = args.interval ?? exp.interval ?? (stopTime - startTime) / 1000;
162167

163168
// Run simulation
164-
const result = simulator.simulate(startTime, stopTime, step, {
165-
solver: args.solver as "rk4" | "dopri5" | "bdf" | "auto",
166-
});
167-
const states = result.states;
168-
169-
// Output results
170-
if (args.format === "json") {
171-
const rows = result.t.map((t: number, i: number) => {
172-
const row: Record<string, number> = { time: t };
173-
states.forEach((state: string, vIndex: number) => {
174-
row[state] = result.y[i]?.[vIndex] ?? 0;
175-
});
176-
return row;
169+
const states = Array.from(simulator.stateVars) as string[];
170+
if (args.realtime !== undefined && args.realtime > 0) {
171+
if (args.format === "csv") {
172+
const header = ["time", ...states].join(",");
173+
process.stdout.write(header + "\n");
174+
}
175+
// Stream results
176+
const res = await simulator.simulateAsync(startTime, stopTime, step, {
177+
solver: args.solver as "rk4" | "dopri5" | "bdf" | "auto",
178+
realtimeFactor: args.realtime,
177179
});
178-
process.stdout.write(JSON.stringify(rows, null, 2) + "\n");
180+
// Print everything at the end for JSON. If we want we can stream CSV.
181+
if (args.format === "json") {
182+
const rows = res.t.map((t: number, i: number) => {
183+
const row: Record<string, number> = { time: t };
184+
states.forEach((state: string, vIndex: number) => {
185+
row[state] = res.y[i]?.[vIndex] ?? 0;
186+
});
187+
return row;
188+
});
189+
process.stdout.write(JSON.stringify(rows, null, 2) + "\n");
190+
} else {
191+
for (let i = 0; i < res.t.length; i++) {
192+
const values = [res.t[i], ...states.map((_: string, vIndex: number) => res.y[i]?.[vIndex] ?? 0)];
193+
process.stdout.write(values.join(",") + "\n");
194+
}
195+
}
179196
} else {
180-
// CSV format
181-
const header = ["time", ...states].join(",");
182-
process.stdout.write(header + "\n");
183-
for (let i = 0; i < result.t.length; i++) {
184-
const values = [result.t[i], ...states.map((_: string, vIndex: number) => result.y[i]?.[vIndex] ?? 0)];
185-
process.stdout.write(values.join(",") + "\n");
197+
const result = simulator.simulate(startTime, stopTime, step, {
198+
solver: args.solver as "rk4" | "dopri5" | "bdf" | "auto",
199+
});
200+
201+
// Output results
202+
if (args.format === "json") {
203+
const rows = result.t.map((t: number, i: number) => {
204+
const row: Record<string, number> = { time: t };
205+
states.forEach((state: string, vIndex: number) => {
206+
row[state] = result.y[i]?.[vIndex] ?? 0;
207+
});
208+
return row;
209+
});
210+
process.stdout.write(JSON.stringify(rows, null, 2) + "\n");
211+
} else {
212+
// CSV format
213+
const header = ["time", ...states].join(",");
214+
process.stdout.write(header + "\n");
215+
for (let i = 0; i < result.t.length; i++) {
216+
const values = [result.t[i], ...states.map((_: string, vIndex: number) => result.y[i]?.[vIndex] ?? 0)];
217+
process.stdout.write(values.join(",") + "\n");
218+
}
186219
}
187220
}
188221
},

0 commit comments

Comments
 (0)