1function [QNclass_t, UNclass_t, TNclass_t] = getTranAvg(self,Qt,Ut,Tt)
2% [QNCLASS_T, UNCLASS_T, TNCLASS_T] = GETTRANAVG(SELF,QT,UT,TT)
3% Returns transient mean performance metrics over time
5% @brief Computes transient queue length, utilization, and throughput time series
7% This method returns transient performance metrics (time-dependent averages)
8%
for each station and job
class. The transient analysis tracks how metrics
9% evolve from the initial state toward steady state over the specified time span.
11% The Fluid solver uses ODE-based mean-field approximations to compute transient
12% behavior efficiently. The method returns different data structures depending on
13% whether optional handles are provided.
15% @param self SolverFluid instance (must have timespan configured, e.g.,
16% SolverFluid(model,
'timespan', [0, 50]))
17% @param Qt (optional) Queue length handle from previous computation. If provided,
18% returns cached results. Otherwise computes
new QN(t).
19% @param Ut (optional) Utilization handle. If provided, uses cached results.
20% Otherwise computes
new UN(t).
21% @param Tt (optional) Throughput handle. If provided, uses cached results.
22% Otherwise computes
new TN(t).
24% @
return QNclass_t Nested cell array of queue length time series
25% - Structure: {station_1, station_2, ...} where each station contains
26% {class_1_timeseries, class_2_timeseries, ...}
27% - Each element
is a vector of queue lengths at each time point
28% - Shape: [num_stations][num_classes] with each element a time-series array
30% @
return UNclass_t Nested cell array of utilization time series
31% - Same structure as QNclass_t but containing utilization values
33% @
return TNclass_t Nested cell array of throughput time series
34% - Same structure as QNclass_t but containing throughput values
36% @note Transient analysis
is only available
for certain solvers (CTMC, Fluid, JMT).
37% Must configure timespan when creating solver instance:
38% solver = SolverFluid(model,
'timespan', [0, 100]);
40% @warning The Fluid approximation
is mean-field based and provides estimates
41% rather than exact transient probabilities. Use CTMC
for small models
42% requiring exact transient analysis.
44% @see getTranHandles - Get result handles
for transient metrics
45% @see getAvg - Get steady-state average metrics
49% model = Network(
'example');
50% % ... model construction ...
51% solver = SolverFluid(model,
'timespan', [0, 50]);
52% [QN_t, UN_t, TN_t] = solver.getTranAvg();
54% % Access queue length time series
for station 0,
class 1
55% qlen_time_series = QN_t{1}{2};
56% plot(qlen_time_series);
59% Copyright (c) 2012-2026, Imperial College London
62% temporarily switch to closing method
64 [Qt,Ut,Tt] = self.getTranHandles;
67options = self.options;
68% Force MATLAB path
for transient analysis (Java path only produces steady-state)
69self.options.lang =
'matlab';
71% see _kb/06-solver-catalog.md for rationale
73hasCache = any(sn.nodetype == NodeType.Cache);
75% see _kb/06-solver-catalog.md for rationale
76self.options.config.nhpp_sched = local_detect_nhpp(self.model, sn);
79 case {
'default',
'matrix',
'closing',
'rmf',
'fluid.rmf'}
80 % These methods can
switch to closing silently
for the queueing
81 % transient (RMF caches keep their transient via cacheqn_tran below).
82 self.options.method =
'closing';
83 case {
'tbi',
'fluid.tbi'}
84 % TBI integrates the closing ODEs by cell decomposition and
85 % produces a genuine transient; keep the method as
is.
87 line_warning(mfilename,
'getTranAvg is not offered by the specified method. Setting the solution method to ''''closing
''''.\n');
88 self.options.method =
'closing';
93 % The cache carries its own transient through the RMF drift.
94 tranopts = self.options;
95 tranopts.method =
'rmf';
96 tranopts.timespan = options.timespan;
97 [tcache, hitprob_t, missprob_t, caches, arate] = solver_fld_cacheqn_tran(sn, tranopts);
98 self.result.CacheTran =
struct(
't', tcache,
'hitprob', hitprob_t, ...
99 'missprob', missprob_t,
'nodes', caches,
'arate', arate);
100 % see _kb/06-solver-catalog.md for rationale
102 [QNclass_t, UNclass_t, TNclass_t] = getTranAvg@NetworkSolver(self,Qt,Ut,Tt);
104 [QNclass_t, UNclass_t, TNclass_t] = local_const_tran(self, options.timespan);
107 [QNclass_t, UNclass_t, TNclass_t] = getTranAvg@NetworkSolver(self,Qt,Ut,Tt);
110self.options = options;
113function sched = local_detect_nhpp(model, sn)
114% Build the nhpp_sched
struct array (station index in sn station space, class,
115% process handle)
for every EXT/source station carrying a non-homogeneous
116% arrival process (identified by the getRateSchedule method, as in
117% refreshProcessRepresentations). Empty when there
is none.
119for i = 1:sn.nstations
120 if sn.sched(i) ~= SchedStrategy.EXT
123 node = model.nodes{sn.stationToNode(i)};
124 if ~isa(node,
'Source')
127 for c = 1:sn.nclasses
128 if numel(node.input.sourceClasses) < c || isempty(node.input.sourceClasses{c})
131 proc = node.input.sourceClasses{c}{end};
132 if ismethod(proc,
'getRateSchedule')
133 entry = struct('station', i, 'class', c, 'nhpp', proc);
137 sched(end+1) = entry; %
#ok<AGROW>
144function [QNt, UNt, TNt] = local_const_tran(self, timespan)
145% Build constant transient handles from the steady-state solution, for cache
146% networks whose queueing part has no fluid dynamics to integrate.
147solver = FLD(self.model, 'method', 'rmf');
148[QN, UN, ~, TN] = solver.getAvg();
149M = size(QN, 1); K = size(QN, 2);
150t0 = timespan(1);
if isinf(t0), t0 = 0; end
151tcol = [t0; timespan(2)];
152QNt = cell(M, K); UNt = cell(M, K); TNt = cell(M, K);
155 QNt{i,r} = [QN(i,r); QN(i,r)]; QNt{i,r}(:,2) = tcol;
156 UNt{i,r} = [UN(i,r); UN(i,r)]; UNt{i,r}(:,2) = tcol;
157 TNt{i,r} = [TN(i,r); TN(i,r)]; TNt{i,r}(:,2) = tcol;