1function [nonfjmodel, fjclassmap, fjforkmap, fanout] = mmt(model, forkLambda)
2% build a model with fork-joins replaced by routers and delays and
3% parallelism simulated by artificial classes
4% forkLambda(s)
is the arrival rate of artificial
class s
5% s = fjclassmap(r)
for auxiliary
class r gives the index s of the original class
6% f = fjforkmap(r)
for auxiliary
class r gives the index of the associated fork node f
7% fo = fanout(r)
is the number of output jobs across all links
for the (fork f,
class s) pair modelled by auxiliary
class r
9%%
this has been migrated to Java inside FJ.java as mmt
13 forkLambda = GlobalConstants.FineTol * ones(1,sn.nclasses);
18% we create an equivalent model without fj stations
19nonfjmodel = model.copy();
20nonfjmodel.allowReplace =
true;
21P = nonfjmodel.getLinkedRoutingMatrix;
22nonfjmodel.resetNetwork(
true);
23nonfjmodel.resetStruct();
25 line_error(mfilename,
'SolverMVA can process fork-join networks only if their routing topology has been generated using Network.link.');
27Vnodes = cellsum(sn.nodevisits);
29forkIndexes = find(sn.nodetype == NodeType.Fork)
';
30% replaces forks and joins with routers
34 if length(model.nodes{f}.output.outputStrategy{r})>2
35 origfanout(f,r) = length(model.nodes{f}.output.outputStrategy{r}{3});
37 P{r,s}(f,:) = P{r,s}(f,:) / origfanout(f,r);
43 % replace Join with a Router
44 nonfjmodel.nodes{f} = Router(nonfjmodel, nonfjmodel.nodes{f}.name);
45 % replace Fork with a StatelessClassSwitcher that doesn't
47 %nonfjmodel.nodes{f} = ClassSwitch(nonfjmodel, nonfjmodel.nodes{f}.name, eye(sn.nclasses));
48 forkedClasses{f,1} = find(Vnodes(f,:)>0); %#ok<AGROW>
50for j=find(sn.nodetype == NodeType.Join)
'
51 % replace Join with an Infinite Server
52 nonfjmodel.nodes{j} = Delay(nonfjmodel, nonfjmodel.nodes{j}.name);
53 nonfjmodel.stations{model.nodes{j}.stationIndex} = nonfjmodel.nodes{j};
54 for c=1:length(nonfjmodel.classes)
55 nonfjmodel.nodes{j}.setService(nonfjmodel.classes{c},Immediate());
58nonfjmodel.stations={nonfjmodel.stations{1:model.getNumberOfStations}}'; % remove automatically added station and put it where the join was
59%
if they don
't exist already, add source and sink
60if nonfjmodel.hasOpenClasses
61 source = nonfjmodel.getSource;
62 sink = nonfjmodel.getSink;
64 source = Source(nonfjmodel,'Source
');
65 sink = Sink(nonfjmodel,'Sink
');
69 P{r,s}(length(nonfjmodel.nodes),length(nonfjmodel.nodes)) = 0;
70 P{s,r}(length(nonfjmodel.nodes),length(nonfjmodel.nodes)) = 0;
73nonfjmodel.connections = zeros(length(nonfjmodel.nodes));
76 % find join associated to fork f
77 joinIdx = find(sn.fj(f,:));
79 line_error(mfilename,'SolverMVA supports at present only a single join station per fork node.
');
81 % find chains associated to classes forked by f
82 forkedChains = find(sum(sn.chains(:,forkedClasses{f}),2));
84 % create a
new open
class for each class in forkedChains
86 inchain = find(sn.chains(fc,:)); inchain = inchain(:)
';
88 oclass{end+1} = OpenClass(nonfjmodel,[nonfjmodel.classes{r}.name,'.
',nonfjmodel.nodes{f}.name]); %#ok<AGROW>
89 fjclassmap(oclass{end}.index) = nonfjmodel.classes{r}.index;
90 fjforkmap(oclass{end}.index) = f;
91 s = fjclassmap(oclass{end}.index); % auxiliary class index
92 if model.nodes{f}.output.tasksPerLink > 1
93 line_warning(mfilename, 'There are no synchronisation delays implemented in MMT for multiple tasks per link. Results may be inaccurate.
');
95 fanout(oclass{end}.index) = origfanout(f,r)*model.nodes{f}.output.tasksPerLink;
96 if sn.nodevisits{fc}(f,r) == 0
97 source.setArrival(oclass{end},Disabled.getInstance);
99 source.setArrival(oclass{end},Exp(forkLambda(r)));
101 % joins are now Delays, let us set their service time
104 switch sn.nodetype(i)
106 nonfjmodel.nodes{i}.setService(oclass{end},Immediate());
107 case {NodeType.Source, NodeType.Fork}
110 nonfjmodel.nodes{i}.setService(oclass{end},model.nodes{i}.getService(model.classes{r}).copy());
119 P{oclass{find(r==inchain,1)},oclass{find(s==inchain,1)}} = P{r,s};
124 P{oclass{find(r==inchain,1)},oclass{find(s==inchain,1)}}(source,:) = 0.0;
125 P{oclass{find(r==inchain,1)},oclass{find(s==inchain,1)}}(nonfjmodel.nodes{joinIdx},:) = 0.0;
127 P{oclass{find(r==inchain,1)},oclass{find(r==inchain,1)}}(source, nonfjmodel.nodes{f}) = 1.0;
128 P{oclass{find(r==inchain,1)},oclass{find(r==inchain,1)}}(nonfjmodel.nodes{joinIdx},sink) = 1.0;
134 for r=1:length(nonfjmodel.nodes{f}.output.outputStrategy)
135 if strcmp(nonfjmodel.nodes{f}.output.outputStrategy{r}{2},RoutingStrategy.RAND)
136 nonfjmodel.nodes{f}.output.outputStrategy{r}{1} = nonfjmodel.classes{r}.name;
137 nonfjmodel.nodes{f}.output.outputStrategy{r}{2} = RoutingStrategy.DISABLED;