1function [outspace, outrate, outprob, eventCache] = afterEventJoin(sn, ind, inspace, event,
class, isSimulation, eventCache, key)
2% [OUTSPACE, OUTRATE, OUTPROB, EVENTCACHE] = AFTEREVENTJOIN(SN, IND, INSPACE, EVENT, CLASS, ISSIMULATION, EVENTCACHE, KEY)
4% Handle afterEvent logic
for Join stations on FJ-augmented structs
5% (see ModelAdapter.fjtag). The join state
is a plain per-
class count
6% vector [n_1..n_R] of buffered jobs: auxiliary-class entries
count the
7% sibling tasks waiting for synchronization.
9% ARV (passive): buffer
the arriving job/sibling.
10% DEP in an original class r (active, immediate): enabled when a plain
11% class-r job
is buffered, or when some tag t has
the full required
12% sibling multiset present (all B branches, identity matching by tag).
13% The firing consumes
the siblings of
the LOWEST complete tag and lets
14% one class-r job depart;
the r->destination move
is the regular sync
15% pairing generated by refreshSync from
the join routing.
17% Copyright (c) 2012-2026, Imperial College London
25n = inspace(:,(end-R+1):end); % per-
class counts (rows x R)
29 n(:,class) = n(:,class) + 1;
31 outrate = -1*ones(size(outspace,1),1); % passive action, rate
is unspecified
34 if iscell(sn.nodeparam) && length(sn.nodeparam) >= ind && isstruct(sn.nodeparam{ind}) && isfield(sn.nodeparam{ind},'fj')
37 % auxiliary sibling classes never depart individually: they are
38 % consumed only by
the original-
class join firing below
41 for rr=fjp.origclasses(:)
'
42 if ~isempty(fjp.auxmatrix{rr}) && any(any(fjp.auxmatrix{rr} == class))
51 outspace = zeros(0,R);
57 % plain (non-forked) job buffered in the departing class
58 nrow(class) = nrow(class) - 1;
59 outspace(end+1,:) = nrow; %#ok<AGROW>
60 outrate(end+1,1) = GlobalConstants.Immediate; %#ok<AGROW>
61 outprob(end+1,1) = 1; %#ok<AGROW>
62 elseif ~isempty(fjp) && length(fjp.auxmatrix) >= class && ~isempty(fjp.auxmatrix{class})
63 auxm = fjp.auxmatrix{class}; % B x T matrix of auxiliary class indices
64 req = fjp.required{class}; % B x 1 required siblings per branch
68 if all(nrow(auxm(:,t)) >= req(:)')
69 tstar = t; % lowest complete tag, canonical consumption
74 nrow(auxm(:,tstar)) = nrow(auxm(:,tstar)) - req(:)
';
75 outspace(end+1,:) = nrow; %#ok<AGROW>
76 outrate(end+1,1) = GlobalConstants.Immediate; %#ok<AGROW>
77 outprob(end+1,1) = 1; %#ok<AGROW>
89 if nargin>=7 && isobject(eventCache)
90 eventCache(key) = {outprob, outspace, outrate};
92 if size(outspace,1) > 1
93 tot_rate = sum(outrate);
94 cum_rate = cumsum(outrate) / tot_rate;
95 firing_ctr = 1 + max([0,find( rand > cum_rate' )]); % select action
96 outspace = outspace(firing_ctr,:);
97 outrate = sum(outrate);
98 outprob = outprob(firing_ctr,:);