1function res = runTransientJson(self, numEvents)
2% RES = RUNTRANSIENTJSON(NUMEVENTS)
3% Run a fully JSON-mediated transient LDES simulation over
the horizon
4% [0, samples] (or [0, numEvents] when numEvents>0) with trajectory export,
5% and
return the parsed trajectory. Mirrors
the Python-native _run_transient.
8% .t - (nTimePoints x 1) time vector, or [] if none
9% .QNt - 1 x Nouter cell; RES.QNt{i}
is a 1 x R cell whose {r} entry
is the
10% (nTimePoints x 2) [value, time] trajectory of
class r at
the i-th
11% stateful node, or []
if absent. Nouter matches
the engine
's outer
12% transient dimension (stateful-node major, as consumed by sample()).
14options = self.getOptions;
15% The horizon is passed explicitly via --timespan; options.samples (the
16% steady-state event budget) is left untouched since the engine ignores it
19if nargin >= 2 && ~isempty(numEvents) && numEvents > 0
22extraFlags = {'--timespan
', sprintf('0,%.10g
', S), '--trajectory
'};
24% Ensemble transient: a single realization is not the transient mean E[N](t)
25% (no time-ergodicity at fixed t). When replications > 1 is requested, drive
26% the engine's parallel analyzer via --replications so
the per-bucket QNt/UNt/
27% TNt are averaged across independent replications. Read from options.replications
28% or options.config.replications;
default (absent/<=1) keeps
the single-path run.
30if isfield(options,
'replications') && ~isempty(options.replications)
31 reps = options.replications;
32elseif isfield(options, 'config') && isfield(options.config, 'replications') ...
33 && ~isempty(options.config.replications)
34 reps = options.config.replications;
37 extraFlags{end+1} =
'--replications';
38 extraFlags{end+1} = sprintf(
'%d', round(reps));
39 if isfield(options,
'config') && isfield(options.config,
'numthreads') ...
40 && ~isempty(options.config.numthreads) && options.config.numthreads > 0
41 extraFlags{end+1} =
'--numthreads';
42 extraFlags{end+1} = sprintf(
'%d', round(options.config.numthreads));
46data = self.solveCli(options, extraFlags);
48res =
struct(
't', [],
'QNt', {{}});
49if ~isstruct(data) || ~isfield(data,
'transient') || isempty(data.transient)
53if isfield(tran, 't') && ~isempty(tran.t)
54 tvec = ldesJson2mat(tran.t, [], []);
57if isfield(tran, 'QNt') && ~isempty(tran.QNt)
58 sn = self.model.getStruct;
59 Nouter = sn.nstateful;
61 % Normalize into an Nouter x R cell of [nRows x 2] matrices, then repackage
62 % as a 1 x Nouter cell of 1 x R class-cells (
the layout sample() consumes).
63 grid = ldesTrajCell(tran.QNt, Nouter, R);
64 res.QNt = cell(1, Nouter);
66 classCells = cell(1, R);
68 classCells{r} = grid{i, r};
70 res.QNt{i} = classCells;