1function ctx = afterEventInit(sn)
2% CTX = AFTEREVENTINIT(SN)
3% Precomputes
the loop-invariant setup of State.afterEvent so that hot
4% callers (e.g.,
the solver_ssa Gillespie loop, which re-evaluates every
5% synchronization at every step) avoid re-deriving it on each call.
7% IMPORTANT: ctx caches sn.nservers, sn.cap and sn.classcap. It must be
8% built AFTER any caller-side rewrite of these fields (solver_ssa rewrites
9% them in its preamble: Inf servers at delay
nodes and open-class cutoffs)
10% and AFTER sn_nonmarkov_toph, and
the SAME sn must be passed to afterEvent
11% alongside ctx. Building ctx from a stale sn silently drops blocking and
12% server-
count semantics.
14% Copyright (c) 2012-2026, Imperial College London
23ctx.phasessz = sn.phasessz;
24ctx.phaseshift = sn.phaseshift;
30ctx.classcap = sn.classcap;
32lldscaling = sn.lldscaling;
34 lldlimit = max(sum(sn.nclosedjobs),1);
35 lldscaling = ones(M,lldlimit);
37 lldlimit = size(lldscaling,2);
39ctx.lldscaling = lldscaling;
40ctx.lldlimit = lldlimit;
42% sn.cdscaling holds a
class-dependence handle only
for the stations that
43% declare one;
the others are left empty (see getLimitedClassDependence), since
44% a constant 1
is not a valid
class-dependent RATE. The state machinery indexes
45% every station unconditionally, so fill
the gaps with
the neutral scaling here.
46cdscaling = sn.cdscaling;
48 cdscaling = cell(M,1);
52 if i > numel(cdscaling) || isempty(cdscaling{i})
53 cdscaling{i} = neutral;
56ctx.cdscaling = cdscaling;
58ctx.ismkvmod =
false(sn.nnodes,1);
59ctx.ismkvmodclass = cell(sn.nnodes,1);
62 ist = sn.nodeToStation(ind);
63 ctx.ismkvmod(ind) = any(sn.procid(ist,:)==ProcessType.MAP | sn.procid(ist,:)==ProcessType.MMPP2);
64 ismkvmodclass = zeros(R,1);
66 ismkvmodclass(r) = any(sn.procid(ist,r)==ProcessType.MAP | sn.procid(ist,r)==ProcessType.MMPP2);
68 ctx.ismkvmodclass{ind} = ismkvmodclass;