1function tf = isPhysicalCapacity(sn, ist,
class)
2% TF = ISPHYSICALCAPACITY(SN, IST, CLASS)
4% True when
the capacity bound at station IST
for CLASS
is a PHYSICAL finite
5% capacity (setCapacity/setClassCapacity), as opposed to a state-space CUTOFF
6% imposed on an open
class only to bound enumeration.
8% This distinction matters because
the producer
's capacity/classcap arguments
9% have the open-class cutoff folded in: solver_ssa overwrites sn.cap/sn.classcap
10% with min(cutoff, physical), so at the cutoff boundary they are finite even
11% when there is no physical cap. Treating a cutoff boundary as a physical one
12% would turn a state-space truncation into a self-loop loss (wrong ArvR and a
13% perturbed sample path). Only a physical cap should trigger the loss/block
14% refusal semantics; a cutoff-only refusal must fall back to the pre-change
15% truncation (place the job, let the en_o capacity filter delete the row).
17% The reliable in-producer signal is the DROP RULE. refreshCapacity sets a
18% finite-capacity drop rule (DROP, or a blocking/retrial rule) exactly when the
19% station has a physical finite capacity for the class; an open class bounded
20% only by the cutoff keeps the WAITQ default. So a non-WAITQ, non-unset drop
21% rule marks a physical capacity. (A user who explicitly sets WAITQ on a
22% physical cap is the one ambiguous case; it is already ill-defined -- CTMC
23% drops, JMT blocks -- and is treated here as a cutoff, i.e. truncated.)
25% Copyright (c) 2012-2026, Imperial College London
28if isempty(sn.droprule) || size(sn.droprule,1) < ist || size(sn.droprule,2) < class
32dr = sn.droprule(ist,class);
33tf = dr ~= DropStrategy.WAITQ && dr ~= 0;