1function [CNchain,XNchain] = getAvgSys(self,R,T)
2% [CNCHAIN,XNCHAIN] = GETAVGSYS(SELF,R,T)
4% Return average system metrics at steady state
6% Copyright (c) 2012-2026, Imperial College London
9sn = self.model.getStruct();
11 R = self.getAvgRespTHandles;
12 T = self.getAvgTputHandles;
14[~,~,RN,TN] = self.getAvg([],[],R,T,[],[]);
15RN(sn.nodeToStation(find(sn.nodetype == NodeType.Join)), :) = 0;
16for f=find(sn.nodetype == NodeType.Fork)
'
17 % find join associated to fork f
18 joinIdx = find(sn.fj(f,:));
20 % No join nodes for this fork, no synchronisation delay
24 inchain = sn.inchain{c};
25 nJobsChain = sum(sn.njobs(find(sn.chains(c,:)))); %#ok<FNDSB>
26 if isinf(nJobsChain) % limit this calculation to open chains as we can use Little's Law
for closed chains
28 if RN(sn.nodeToStation(joinIdx), r) == 0
29 % Find the parallel paths coming out of the fork
30 %[ri, stat, RN] = ModelAdapter.paths(sn, self.model.getLinkedRoutingMatrix{r,r}, f, joinIdx, r, RN, 0, []);
31 [ri, stat, RN] = ModelAdapter.pathsCS(sn, cell2mat(self.model.getLinkedRoutingMatrix), f, joinIdx, r, RN, 0, []);
34 parallel_branches = length(ri);
35 for pow=0:(parallel_branches - 1)
36 current_sum = sum(1./sum(nchoosek(lambdai, pow + 1),2));
37 d0 = d0 + (-1)^pow * current_sum;
39 RN(sn.nodeToStation(joinIdx), r) = d0; %
this also includes the mean time in the fork section
for class r
40 RN(stat, r) = 0; %
this is already counted in d0
48completes =
true(1,sn.nclasses);
50 completes(r) = T{refstats(r),r}.class.completes;
53%
if any(isinf(sn.njobs
')) % if the model has any open class
54% TODO: this could be optimised by computing the statistics
58alpha = zeros(sn.nstations,sn.nclasses);
59CNclass = zeros(1,sn.nclasses);
61 inchain = sn.inchain{c};
64 if ~isempty(RN) % if not empty
66 if ~(isinf(sn.njobs(r)) && i==sn.refstat(r)) % if not source
67 CNclass(r) = CNclass(r) + sn.visits{c}(sn.stationToStateful(i),r)*RN(i,r)/sn.visits{c}(sn.stationToStateful(sn.refstat(r)),r);
75 inchain = sn.inchain{c};
76 completingclasses = sn.chains(c,:) & completes;
79 for k=intersect(find(sn.refclass), inchain) % for all classes within the chain (a class belongs to a single chain, the reference station must be identical for all classes within a chain )
80 alpha(i,k) = alpha(i,k) + sn.visits{c}(sn.stationToStateful(i),k)/sum(sn.visits{c}(sn.stationToStateful(sn.refstat(k)),completingclasses));
83 for k=inchain % for all classes within the chain (a class belongs to a single chain, the reference station must be identical for all classes within a chain )
84 alpha(i,k) = alpha(i,k) + sn.visits{c}(i,k)/sum(sn.visits{c}(sn.stationToStateful(sn.refstat(k)),completingclasses));
89alpha(~isfinite(alpha))=0;
92% compute average chain metrics
93CNchain = zeros(1,sn.nchains);
94XNchain = zeros(1,sn.nchains);
96 inchain = sn.inchain{c};
97 completingclasses = find(sn.chains(c,:) & completes);
100 % all classes in same chain must share the same refstation, so we use the first one
101 ref = refstats(inchain(1));
102 % we now compute the incoming system throughput to the
103 % reference station from completing classes
105 for r=completingclasses(:)'
106 if any(intersect(find(sn.refclass), inchain))
107 for s=intersect(find(sn.refclass), inchain)
109 XNchain(c) = XNchain(c) + sn.rt((i-1)*sn.nclasses + r, (ref-1)*sn.nclasses + s )*TN(i,r);
115 XNchain(c) = XNchain(c) + sn.rt((i-1)*sn.nclasses + r, (ref-1)*sn.nclasses + s )*TN(i,r);
123 % If this is a closed chain we simply apply Little's law
124 nJobsChain = sum(sn.njobs(find(sn.chains(c,:)))); %#ok<FNDSB>
126 if length(inchain) ~= length(completingclasses)
127 line_error(mfilename,
'Edge-based chain definition not yet supported for open queueing networks.');
129 % we use nan sum to disregard response at stations where
130 % the
class is not defined
131 % CNchain(c) = sumfinite(alpha(refstats(inchain(1)),inchain).*CNclass(inchain));
133 CNchain(c) = sumfinite(alpha(refstats(inchain(1)),inchain).*CNclass(inchain));
135 CNchain(c) = nJobsChain/XNchain(c);
138self.result.XN = XNchain;
139self.result.CN = CNchain;