LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
solver_fluid.m
1function [QN,xvec_it,QNt,UNt,xvec_t,t,iters,runtime] = solver_fluid(sn, options)
2% [QN,XVEC_IT,QNT,UNT,XVEC_T,T,ITERS,RUNTIME] = SOLVER_FLUID(QN, OPTIONS)
3
4% Copyright (c) 2012-2026, Imperial College London
5% All rights reserved.
6
7M = sn.nstations; %number of stations
8K = sn.nclasses; %number of classes
9N = sn.nclosedjobs; %population
10Mu = sn.mu;
11Phi = sn.phi;
12PH = sn.proc;
13sched = sn.sched;
14rt = sn.rt;
15S = sn.nservers;
16NK = sn.njobs'; %initial population
17
18% NHPP (non-homogeneous Poisson) sources store proc as the {breakpoints,rates,
19% cyclic} schedule, not a {D0,D1} MAP, and pie = NaN. The fluid model treats
20% such a source as a single-phase exponential at its nominal (time-average)
21% rate mu (already in sn.mu); the time-varying intensity lambda(t) is applied
22% separately by the per-event rate multiplier (solver_fluid_ratemult). Replace
23% the schedule with the equivalent 1-phase exponential MAP so the closing-rate
24% builder (ode_rate_base -> map_pie) sees a valid Markovian representation.
25if isfield(sn,'procid')
26 for ist = 1:M
27 for k = 1:K
28 if sn.procid(ist,k) == ProcessType.NHPP && ~isempty(Mu{ist}{k}) ...
29 && ~isnan(Mu{ist}{k}(1))
30 lam = Mu{ist}{k}(1);
31 PH{ist}{k} = {-lam, lam};
32 Phi{ist}{k} = 1;
33 end
34 end
35 end
36end
37
38match = zeros(M,K); % indicates whether a class is served at a station
39for ist = 1:M
40 for k = 1:K
41 if isnan(Mu{ist}{k})
42 Mu{ist}{k} = [];
43 Phi{ist}{k}=[];
44 end
45 match(ist,k) = sum(rt(:, (ist-1)*K+k)) > 0;
46 end
47 %Set number of servers in delay station = population
48 if isinf(S(ist))
49 S(ist) = N;
50 end
51end
52
53%% initialization
54% Wall-clock time budget (options.timeout, seconds; Inf = no budget). The ODE
55% iteration in solver_fluid_iteration breaks when toc(Tstart) > max_time.
56if isfield(options,'timeout') && ~isempty(options.timeout) && isfinite(options.timeout) && options.timeout > 0
57 max_time = options.timeout;
58else
59 max_time = Inf;
60end
61Tstart = tic;
62
63%phases = sn.phases;
64phases = zeros(M,K);
65for ist = 1:M
66 for k = 1:K
67 phases(ist,k) = length(Mu{ist}{k});
68 end
69end
70
71slowrate = zeros(M,K);
72for ist = 1:M
73 for k = 1:K
74 if ~isempty(Mu{ist}{k})
75 slowrate(ist,k) = min(Mu{ist}{k}(:)); %service completion (exit) rates in each phase
76 else
77 slowrate(ist,k) = Inf;
78 end
79 end
80end
81
82%NK(isinf(NK))=1e6;
83iters = 0;
84xvec_it = {};
85y0 = [];
86assigned = zeros(1,K); %number of jobs of each class already assigned
87for ist = 1:M
88 for k = 1:K
89 if match(ist,k) > 0 % indicates whether a class is served at a station
90 if isinf(NK(k))
91 if sched(ist)==SchedStrategy.EXT
92 toAssign = 1; % open job pool
93 else
94 toAssign = 0; % set to zero open jobs everywhere
95 end
96 else
97 toAssign = floor(NK(k)/sum(match(:,k)));
98 if sum( match(ist+1:end, k) ) == 0 % if this is the last station for this job class
99 toAssign = NK(k) - assigned(k);
100 end
101 end
102 y0 = [y0, toAssign, zeros(1,phases(ist,k)-1)]; % this is just for PS
103 assigned(k) = assigned(k) + toAssign;
104 else
105 y0 = [y0, zeros(1,phases(ist,k))];
106 end
107 end
108end
109
110if isempty(options.init_sol)
111 xvec_it{iters +1} = y0(:)'; % average state embedded at stage change transitions out of e
112 ydefault = y0(:)'; % not used in this case
113else
114 xvec_it{iters +1} = options.init_sol(:)';
115 ydefault = y0(:)'; % default solution if init_sol fails
116end
117
118%% solve ode
119switch options.method
120 case {'tbi','fluid.tbi'}
121 [xvec_it, xvec_t, t, iters] = solver_fluid_tbi_iteration(sn, N, Mu, Phi, PH, rt, S, xvec_it, ydefault, slowrate, Tstart, max_time, options);
122 otherwise
123 [xvec_it, xvec_t, t, iters] = solver_fluid_iteration(sn, N, Mu, Phi, PH, rt, S, xvec_it, ydefault, slowrate, Tstart, max_time, options);
124end
125
126runtime = toc(Tstart);
127% if options.verbose >= 2
128% if iters==1
129% line_printf('Fluid analysis iteration completed in %0.6f sec [%d iteration]\n',runtime,iters);
130% else
131% line_printf('Fluid analysis iteration completed in %0.6f sec [%d iterations]\n',runtime,iters);
132% end
133% end
134
135% this part assumes PS, DPS, GPS scheduling
136QN = zeros(M,K);
137QNt = cell(M,K);
138Qt = cell(M,1);
139UNt = cell(M,K);
140for ist=1:M
141 Qt{ist} = 0;
142 for k = 1:K
143 shift = sum(sum(phases(1:ist-1,:))) + sum( phases(ist,1:k-1) ) + 1;
144 QN(ist,k) = sum(xvec_it{end}(shift:shift+phases(ist,k)-1));
145 QNt{ist,k} = sum(xvec_t(:,shift:shift+phases(ist,k)-1),2);
146 Qt{ist} = Qt{ist} + QNt{ist,k};
147 % computes queue length in each node and stage, summing the total
148 % number in service and waiting in that station
149 % results are weighted with the stat prob of the stage
150 end
151end
152
153for ist=1:M
154 if sn.nservers(ist) > 0 % not INF
155 for k = 1:K
156 UNt{ist,k} = min(QNt{ist,k} / S(ist), QNt{ist,k} ./ Qt{ist}); % if not an infinite server then this is a number between 0 and 1
157 UNt{ist,k}(isnan(UNt{ist,k})) = 0; % fix cases where qlen is 0
158 end
159 else % infinite server
160 for k = 1:K
161 UNt{ist,k} = QNt{ist,k};
162 end
163 end
164end
165return
166end