LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
refreshCapacity.m
1function [capacity, classcap, droprule] = refreshCapacity(self)
2% [CAPACITY, CLASSCAP, DROPRULE] = REFRESHCAPACITY()
3
4% Copyright (c) 2012-2026, Imperial College London
5% All rights reserved.
6%I = getNumberOfStatefulNodes(self);
7M = getNumberOfStations(self);
8K = getNumberOfClasses(self);
9C = self.sn.nchains;
10% set zero buffers for classes that are disabled
11classcap = Inf*ones(M,K);
12chaincap = Inf*ones(M,K);
13capacity = zeros(M,1);
14droprule = DropStrategy.WAITQ*ones(M,K);
15sn = self.sn;
16njobs = sn.njobs;
17rates = sn.rates;
18for c = 1:C
19 inchain = sn.inchain{c};
20 for r = inchain
21 chainCap = sum(njobs(inchain));
22 for ist=1:M
23 station = self.getStationByIndex(ist);
24
25 if sn.nodetype(sn.stationToNode(ist)) ~= NodeType.Source
26 % Guard against dropRule array not having entry for class r.
27 % A 0 also means "not set": assigning dropRule(k) for a class k
28 % beyond the current length grows the array and fills the gap
29 % with 0, which is not a DropStrategy member (WAITQ is -1), so
30 % those classes must fall through to the default below rather
31 % than leak a 0 into sn.droprule.
32 if length(station.dropRule) >= r && ~isempty(station.dropRule(r)) ...
33 && station.dropRule(r) ~= 0
34 stationDropRule = station.dropRule(r);
35 else
36 stationDropRule = [];
37 end
38 % An EXPLICIT setDropRule(WAITQ) at a plain finite buffer
39 % reachable by an OPEN class asks for something LINE does not
40 % implement: the arrival should wait until the buffer frees, but
41 % there is no upstream queue to wait in (the Source is an
42 % infinite generator). No solver honours it -- SolverCTMC drops
43 % the arrival, SolverJMT blocks at the Source and ignores the cap
44 % -- so reject rather than pick one silently. Only the explicit
45 % rule is rejected: the WAITQ marker that this function derives
46 % below for a no-buffer station or a closed class is untouched,
47 % as are the blocking policies LINE does implement (BAS/BBS/RSRD).
48 % Place and Join write the WAITQ marker themselves (Place in its
49 % constructor, for every class), so for those nodes the marker is
50 % an internal default and NOT a user request: exclude them, or a
51 % bounded place would be rejected for a rule its user never set.
52 isUserRuleNode = ~isa(station, 'Place') && ~isa(station, 'Join');
53 % classCap(r) == 0 is the "no per-class constraint" sentinel
54 % (a class absent from the station), NOT a real finite buffer, so
55 % it must not count as a finite capacity here -- otherwise the gate
56 % below rejects a WAITQ open class for a station it never visits
57 % (e.g. InitClass at a Delay it does not route to). A real finite
58 % per-class buffer is strictly positive and non-infinite.
59 classCapIsFinite = length(station.classCap) >= r ...
60 && station.classCap(r) > 0 && ~isinf(station.classCap(r));
61 stationCapIsFinite = ~isempty(station.cap) && station.cap >= 0 ...
62 && ~isinf(station.cap) && station.cap < intmax;
63 if isUserRuleNode && ~isempty(stationDropRule) && stationDropRule == DropStrategy.WAITQ ...
64 && isinf(njobs(r)) && (stationCapIsFinite || classCapIsFinite)
65 line_error(mfilename, sprintf(['Station ''%s'' declares setDropRule(WAITQ) for the open class ''%s'' at a finite capacity. ' ...
66 'LINE does not implement waiting-room blocking for an open arrival at a plain finite buffer: no solver honours this combination ' ...
67 '(SolverCTMC drops the arrival, SolverJMT blocks at the Source and ignores the capacity). ' ...
68 'Use setDropRule(DropStrategy.DROP) for a loss station (M/M/1/K), or one of the blocking policies LINE implements ' ...
69 '(DropStrategy.BAS, DropStrategy.BBS, DropStrategy.RSRD) for blocking between stations.'], ...
70 station.getName(), self.classes{r}.getName()));
71 end
72 % Derive the rule from the final station capacity when the user
73 % has not set one, so that the result does not depend on whether
74 % setCapacity was called before or after setService.
75 if isempty(stationDropRule)
76 if isinf(station.cap) || station.cap >= intmax
77 % No buffer: the rule is never consulted.
78 stationDropRule = DropStrategy.WAITQ;
79 elseif station.cap >= 0 && ~isinf(njobs(r))
80 % Real finite buffer and a CLOSED class. DROP would make
81 % the JMT export destroy jobs, and LINE's reference
82 % (CTMC) conserves the closed population instead, so DROP
83 % is not a defensible default here. What a closed class
84 % should do at a full station is currently unsettled in
85 % LINE itself (CTMC blocks and conserves the population,
86 % SSA and LDES drop), so leave the WAITQ marker rather
87 % than decide it here.
88 stationDropRule = DropStrategy.WAITQ;
89 else
90 % Real finite buffer and an OPEN class: LINE's reference
91 % (CTMC) loses the arrival, so DROP.
92 % Also the cap<0 case, which JMT2LINE produces by copying
93 % JMT's "size=-1 means unlimited" sentinel into cap: sn.cap
94 % below then ignores it and falls back to the population,
95 % and saveBufferCapacity emits size=-1, so the rule is
96 % unreachable and its historical DROP value is kept rather
97 % than churning every imported model.
98 stationDropRule = DropStrategy.DROP;
99 end
100 end
101 droprule(ist,r) = stationDropRule;
102 end
103 if isnan(rates(ist,r)) && sn.nodetype(sn.stationToNode(ist)) ~= NodeType.Place
104 classcap(ist,r) = 0;
105 chaincap(ist,c) = 0;
106 else
107 chaincap(ist,c) = chainCap;
108 classcap(ist,r) = chainCap;
109 % Guard against classCap array not having entry for class r
110 if length(station.classCap) >= r && station.classCap(r) >= 0
111 classcap(ist,r) = min(classcap(ist,r), station.classCap(r));
112 end
113 if station.cap >= 0
114 classcap(ist,r) = min(classcap(ist,r), station.cap);
115 end
116 end
117 end
118 end
119end
120for ist=1:M
121 station = self.getStationByIndex(ist);
122 % If station has explicit finite cap set, use it directly (Kendall K notation)
123 % Otherwise use minimum of chain cap sum and class cap sum
124 if station.cap >= 0 && ~isinf(station.cap)
125 % Explicit capacity set - use directly as total capacity
126 capacity(ist,1) = station.cap;
127 else
128 capacity(ist,1) = min([sum(chaincap(ist,:)),sum(classcap(ist,:))]);
129 end
130end
131self.sn.cap = capacity;
132self.sn.classcap = classcap;
133self.sn.droprule = droprule;
134end
Definition fjtag.m:157
Definition Station.m:245