1function [isMmck, muRate] = mam_detect_mmck(sn, ist, K, mmapNode)
2% MAM_DETECT_MMCK Decide
if station ist matches the M/M/c/K assumptions.
4% Returns isMmck=
true (and the shared service rate muRate) only when:
5% - the aggregated arrival
MMAP at the node
is single-phase (i.e. Poisson
6% superposition of class arrivals)
7% - every active class has Exp service (procid==EXP) at the station
8% - all active
classes share the same exponential service rate
14% mmapNode - cell
array {D0, D1, D_c1, D_c2, ...} for the aggregated
15% arrival
MMAP at the node
18% isMmck - logical, true if the M/M/c/K closed form
is exact
19% muRate - the shared service rate (NaN when isMmck
is false)
21% Copyright (c) 2012-2026, Imperial College London
27if isempty(mmapNode) || ~iscell(mmapNode) || size(mmapNode{1}, 1) ~= 1
28 return; % arrivals are not single-phase Poisson superposition
33 if sn.procid(ist, k) ~= ProcessType.EXP
34 % Disabled (NaN rate)
classes are skipped; everything
else must be Exp
35 if isnan(sn.rates(ist, k))
40 if isnan(sn.rates(ist, k)) || sn.rates(ist, k) <= 0
41 continue; % no inflow
for this class
43 muVals(end+1) = sn.rates(ist, k); %#ok<AGROW>
50if max(muVals) - min(muVals) > 1e-9 * max(1, max(muVals))
51 return; % per-
class service rates differ