1function [capacity, classcap, droprule] = refreshCapacity(self)
2% [CAPACITY, CLASSCAP, DROPRULE] = REFRESHCAPACITY()
4% Copyright (c) 2012-2026, Imperial College London
6%I = getNumberOfStatefulNodes(self);
7M = getNumberOfStations(self);
8K = getNumberOfClasses(self);
10% set zero buffers
for classes that are disabled
11classcap = Inf*ones(M,K);
12chaincap = Inf*ones(M,K);
14droprule = DropStrategy.WAITQ*ones(M,K);
18% A chain holding a spawn-target
class is not population-conserving -- see _kb/04-networkstruct.md
19spawnFedChain =
false(1, C);
21 if isprop(self.classes{r0},
'spawnClass') && ~isempty(self.classes{r0}.spawnClass)
22 tIdx = self.classes{r0}.spawnClass.index;
24 if any(sn.inchain{c0} == tIdx)
25 spawnFedChain(c0) =
true;
31 inchain = sn.inchain{c};
33 chainCap = sum(njobs(inchain));
38 station = self.getStationByIndex(ist);
40 if sn.nodetype(sn.stationToNode(ist)) ~= NodeType.Source
41 % Guard against dropRule array not having entry
for class r; a 0 gap-fill
is not a DropStrategy member (WAITQ
is -1)
42 if length(station.dropRule) >= r && ~isempty(station.dropRule(r)) ...
43 && station.dropRule(r) ~= 0
44 stationDropRule = station.dropRule(r);
48 % Explicit setDropRule(WAITQ) at a finite buffer for an open class
is rejected (no solver honours it) -- see _kb/04-networkstruct.md
49 isUserRuleNode = ~isa(station, 'Place') && ~isa(station, 'Join');
50 % classCap(r)==0
is "class absent from station", not a real finite buffer -- must not trip the WAITQ gate below
51 classCapIsFinite = length(station.classCap) >= r ...
52 && station.classCap(r) > 0 && ~isinf(station.classCap(r));
53 stationCapIsFinite = ~isempty(station.cap) && station.cap >= 0 ...
54 && ~isinf(station.cap) && station.cap < intmax;
55 if isUserRuleNode && ~isempty(stationDropRule) && stationDropRule == DropStrategy.WAITQ ...
56 && isinf(njobs(r)) && (stationCapIsFinite || classCapIsFinite)
57 line_error(mfilename, sprintf(['
Station ''%s'' declares setDropRule(WAITQ) for the open class ''%s'' at a finite capacity. ' ...
58 'LINE does not implement waiting-room blocking for an open arrival at a plain finite buffer: no solver honours this combination ' ...
59 '(SolverCTMC drops the arrival, SolverJMT blocks at the Source and ignores the capacity). ' ...
60 'Use setDropRule(DropStrategy.DROP) for a loss station (M/M/1/K), or one of the blocking policies LINE implements ' ...
61 '(DropStrategy.BAS, DropStrategy.BBS, DropStrategy.RSRD) for blocking between stations.'], ...
62 station.getName(), self.classes{r}.getName()));
64 % Derived from the
final station capacity so it doesn
't depend on setCapacity/setService call order
65 if isempty(stationDropRule)
66 if isinf(station.cap) || station.cap >= intmax
67 % No buffer: the rule is never consulted.
68 stationDropRule = DropStrategy.WAITQ;
69 elseif station.cap >= 0 && ~isinf(njobs(r))
70 % Finite buffer + CLOSED class: WAITQ (the correct default is unsettled across LINE's solvers) -- see _kb/04-networkstruct.md
71 stationDropRule = DropStrategy.WAITQ;
73 % Finite buffer + OPEN
class (or cap<0, JMT
's unlimited sentinel): DROP, matching the CTMC reference -- see _kb/04-networkstruct.md
74 stationDropRule = DropStrategy.DROP;
77 droprule(ist,r) = stationDropRule;
79 if isnan(rates(ist,r)) && sn.nodetype(sn.stationToNode(ist)) ~= NodeType.Place
83 chaincap(ist,c) = chainCap;
84 classcap(ist,r) = chainCap;
85 % Guard against classCap array not having entry for class r
86 if length(station.classCap) >= r && station.classCap(r) >= 0
87 classcap(ist,r) = min(classcap(ist,r), station.classCap(r));
90 classcap(ist,r) = min(classcap(ist,r), station.cap);
92 % Finite orbit bounds population at (servers + orbit capacity): a retrial station has no waiting room -- see _kb/04-networkstruct.md
93 if isprop(station,'orbitMaxJobs
') && length(station.orbitMaxJobs) >= r ...
94 && station.orbitMaxJobs(r) >= 0
95 nsrv = sn.nservers(ist);
99 classcap(ist,r) = min(classcap(ist,r), nsrv + station.orbitMaxJobs(r));
106 station = self.getStationByIndex(ist);
107 % If station has explicit finite cap set, use it directly (Kendall K notation)
108 % Otherwise use minimum of chain cap sum and class cap sum
109 if station.cap >= 0 && ~isinf(station.cap)
110 % Explicit capacity set - use directly as total capacity
111 capacity(ist,1) = station.cap;
113 capacity(ist,1) = min([sum(chaincap(ist,:)),sum(classcap(ist,:))]);
116self.sn.cap = capacity;
117self.sn.classcap = classcap;
118self.sn.droprule = droprule;