Per discussion: "test" and "eval" overlap in meaning; "simulations" is more honest about what's actually happening — scripted plant inputs driving a physics sim, then recorded for analysis. Rename scope: - eval/ → simulations/ (tracked as git renames) - Internal references in run.js and README.md updated - wiki/modes/mpc.md link updated Also fixes a log-write bug noticed during the rename: - run.js didn't mkdir simulations/logs/ before createWriteStream, so the stream opened into a potentially non-existent dir and the file never materialised. Added fs.mkdirSync(..., recursive:true). - end() wasn't awaited, so the process could exit before the stream flushed. Now awaits the 'finish' event. Confirmed: 1200 records actually land in simulations/logs/<scenario>.jsonl. - Added simulations/logs/.gitignore so future JSONL artefacts stay out of the repo but the dir remains tracked. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
41 lines
1.4 KiB
JavaScript
41 lines
1.4 KiB
JavaScript
// ASCII table summary of scenario samples.
|
|
// Used by simulations/run.js.
|
|
|
|
function pad(s, n, left = false) {
|
|
s = String(s ?? '');
|
|
if (s.length >= n) return s.slice(0, n);
|
|
return left ? s.padStart(n) : s.padEnd(n);
|
|
}
|
|
|
|
function num(x, digits = 2) {
|
|
return Number.isFinite(x) ? x.toFixed(digits) : '—';
|
|
}
|
|
|
|
function formatTable(records, sampleEvery = 1) {
|
|
if (!records.length) return ' (no records)';
|
|
const header = ['t(s)', 'level(m)', 'vol(m3)', 'dir', 'netFlow(m3/s)', 'src', 'demand', 'safe'];
|
|
const rows = [];
|
|
for (let i = 0; i < records.length; i += sampleEvery) rows.push(records[i]);
|
|
if (rows[rows.length - 1] !== records[records.length - 1]) rows.push(records[records.length - 1]);
|
|
|
|
const widths = [6, 9, 9, 10, 14, 14, 8, 5];
|
|
const lines = [];
|
|
lines.push(header.map((h, i) => pad(h, widths[i], true)).join(' '));
|
|
lines.push(widths.map((w) => '─'.repeat(w)).join(' '));
|
|
for (const r of rows) {
|
|
lines.push([
|
|
pad(r.t, widths[0], true),
|
|
pad(num(r.level, 2), widths[1], true),
|
|
pad(num(r.volume, 2), widths[2], true),
|
|
pad(r.direction ?? '—', widths[3], true),
|
|
pad(num(r.netFlow, 5), widths[4], true),
|
|
pad(r.flowSource ?? '—', widths[5], true),
|
|
pad(num(r.percControl, 0) + '%', widths[6], true),
|
|
pad(r.safetyActive ? '⚠' : '·', widths[7], true),
|
|
].join(' '));
|
|
}
|
|
return lines.map((l) => ' ' + l).join('\n');
|
|
}
|
|
|
|
module.exports = { formatTable };
|