LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
JSIM2LINE.m
1function model = JSIM2LINE(filename,modelName)
2% MODEL = JSIM2LINE(FILENAME,MODELNAME)
3
4% Copyright (c) 2012-2026, Imperial College London
5% All rights reserved.
6T0=tic;
7% import model
8Pref.Str2Num = 'always';
9xDoc = xml_read(filename,Pref);
10try
11 xDoc = xDoc.sim;
12end
13
14% create network
15if nargin<2
16 [~,modelName] = fileparts(xDoc.ATTRIBUTE.name);
17end
18model = Network(modelName);
19
20% create stations
21node_name = cellfun(@(x) x.name, {xDoc.node.ATTRIBUTE},'UniformOutput',false)';
22orig_node_name = node_name;
23for i=1:length(node_name)
24 node_name{i}=strrep(node_name{i},'/','_');
25 node_name{i}=strrep(node_name{i},'\','_');
26end
27
28xsection = {xDoc.node.section};
29strategy = cell(1,length(node_name));
30xsection_par = {};
31xsection_i = {};
32xsection_javaClass = {};
33sink_idx = -1;
34source_idx = -1;
35
36% This is to create the cs elements last, unclear if it affects correctness
37% isStation = ones(1,length(node_name));
38% for i=1:length(node_name)
39% xsection_i{i} = {xsection{i}};
40% xsection_i{i} = xsection_i{i}{1}; % input, service, and output sections of node i
41% xsection_class{i} = {xsection_i{i}.ATTRIBUTE};
42% switch xsection_class{i}{1}.className % input section
43% case {'Buffer'}
44% xsection_i_type{i} = {xsection{i}.ATTRIBUTE};
45% switch xsection_i_type{i}{2}.className
46% case {'StatelessClassSwitcher'}
47% isStation(i) = 0;
48% end
49% end
50% end
51
52%for i=[find(isStation==1), find(isStation==0)]
53for i=1:length(node_name)
54 xsection_i{i} = {xsection{i}};
55 xsection_i{i} = xsection_i{i}{1}; % input, service, and output sections of node i
56 xsection_javaClass{i} = {xsection_i{i}.ATTRIBUTE};
57 switch xsection_javaClass{i}{1}.className % input section
58 case 'JobSink'
59 node{i} = Sink(model, node_name{i});
60 sink_idx = i;
61 case 'RandomSource'
62 node{i} = Source(model, node_name{i});
63 source_idx = i;
64 xrouting{i} = {xsection_i{i}(3).parameter.subParameter.ATTRIBUTE};
65 nSources=1;
66 case 'Join'
67 forkMap=find(cellfun(@any,strfind(cellfun(@class,model.nodes,'UniformOutput',false),'Fork')));
68 if length(forkMap)>1
69 line_error(mfilename,'JSIM2LINE supports at most a single fork-join pair.');
70 end
71 node{i} = Join(model, node_name{i}, node{forkMap});
72 xrouting{i} = {xsection_i{i}(3).parameter.subParameter.ATTRIBUTE};
73 case 'Queue'
74 switch xsection_javaClass{i}{3}.className
75 case 'Fork'
76 node{i} = Fork(model, node_name{i});
77 node{i}.setTasksPerLink(xsection_i{i}(3).parameter(1).value); %jobsPerLink
78 xrouting{i} = {xsection_i{i}(3).parameter(4).subParameter.ATTRIBUTE};
79 otherwise
80 switch xsection_javaClass{i}{2}.className
81 case 'ServiceTunnel'
82 node{i} = Router(model, node_name{i});
83 xrouting{i} = {xsection_i{i}(3).parameter.subParameter.ATTRIBUTE};
84 otherwise
85 xsection_par{i} = {xsection{i}.parameter};
86 xsection_i_par{i} = xsection_i{i}.parameter;
87
88 xsection_i_value{i} = {xsection_i_par{i}.value};
89 xsection_i_par_attr{i} = {xsection_i_par{i}.ATTRIBUTE};
90
91 xsection_i_subpar{i} = {xsection_i_par{i}.subParameter};
92 %if xsection_i_value{i}{1}==-1
93 % node{i} = Router(model, node_name{i});
94 %else
95
96 xsvc{i} = {xsection_i{i}(2).parameter.subParameter};
97 xrouting{i} = {xsection_i{i}(3).parameter.subParameter.ATTRIBUTE};
98
99 % xget_strategy{i} = {xsection_i_par{i}.ATTRIBUTE};
100 % switch xget_strategy{i}{3}.name
101 % case 'LCFSstrategy'
102 % strategy{i} = SchedStrategy.LCFS;
103 % case 'FCFSstrategy'
104 % strategy{i} = SchedStrategy.FCFS;
105 % end
106
107 xput_strategy{i} = xsection_i_par{i};
108 switch xput_strategy{i}(3).ATTRIBUTE.name
109 case 'retrialDistributions'
110 % new XML format from 1.2.0
111 %xretrial_strategy{i}= {xput_strategy{i}(4)};
112 xput_strategy{i}= {xput_strategy{i}(5).subParameter.ATTRIBUTE};
113 otherwise
114 xput_strategy{i}= {xput_strategy{i}(4).subParameter.ATTRIBUTE};
115 end
116 switch xput_strategy{i}{1}.name
117 case 'TailStrategy'
118 strategy{i} = SchedStrategy.FCFS;
119 case 'TailStrategyPriority'
120 strategy{i} = SchedStrategy.HOL;
121 case 'HeadStrategy'
122 strategy{i} = SchedStrategy.LCFS;
123 case 'RandStrategy'
124 strategy{i} = SchedStrategy.SIRO;
125 case 'SJFStrategy'
126 strategy{i} = SchedStrategy.SJF;
127 case 'SEPTStrategy'
128 strategy{i} = SchedStrategy.SEPT;
129 case 'LJFStrategy'
130 strategy{i} = SchedStrategy.LJF;
131 case 'LEPTStrategy'
132 strategy{i} = SchedStrategy.LEPT;
133 end
134
135 xsection_i_type{i} = {xsection{i}.ATTRIBUTE};
136 switch xsection_i_type{i}{2}.className
137 case 'Delay'
138 node{i} = Delay(model, node_name{i});
139 xcapacity = {xsection_i_par{i}.value};
140 node{i}.setCapacity(xcapacity{1}); % buffer size
141 case 'Server'
142 node{i} = Queue(model, node_name{i}, strategy{i});
143 xcapacity = {xsection_i_par{i}.value};
144 node{i}.setCapacity(xcapacity{1}); % buffer size
145 xsection_par_val{i} = {xsection_par{end}{2}.value};
146 node{i}.setNumServers(xsection_par_val{i}{1});
147 switch SchedStrategy.toId(strategy{i})
148 case SchedStrategy.SEPT
149 schedparams{i} = NaN;
150 end
151 case 'PSServer' % requires JMT >= 1.0.2
152 strategy_i_sub={xsection_par{i}{2}.subParameter};
153 strategy_i_sub4=strategy_i_sub{4}; strategy_i_sub4={strategy_i_sub4.ATTRIBUTE};
154 strategy_i_sub5=strategy_i_sub{5};
155 schedparams{i} = cell2mat({strategy_i_sub5.value});
156 r=1; % we assume the strategies are identical across classes
157 switch strategy_i_sub4{r}.name
158 case 'EPSStrategy'
159 strategy{i} = SchedStrategy.PS;
160 case 'DPSStrategy'
161 strategy{i} = SchedStrategy.DPS;
162 case 'GPSStrategy'
163 strategy{i} = SchedStrategy.GPS;
164 case 'EPSStrategyPriority'
165 strategy{i} = SchedStrategy.PSPRIO;
166 case 'DPSStrategyPriority'
167 strategy{i} = SchedStrategy.DPSPRIO;
168 case 'GPSStrategyPriority'
169 strategy{i} = SchedStrategy.GPSPRIO;
170 end
171 node{i} = Queue(model, node_name{i}, strategy{i});
172 xcapacity = {xsection_i_par{i}.value};
173 node{i}.setCapacity(xcapacity{1}); % buffer size
174 xsection_par_val{i} = {xsection_par{end}{2}.value};
175 node{i}.setNumServers(xsection_par_val{i}{1});
176 case 'ClassSwitch'
177 strategy_i_sub={xsection_par{i}{2}.subParameter};
178 strategy_i_sub1=strategy_i_sub{1}; strategy_i_sub1={strategy_i_sub1.subParameter};
179 csMatrix = zeros(length(strategy_i_sub1));
180 for r=1:length(strategy_i_sub1)
181 csMatrix(r,:) = cell2mat({strategy_i_sub1{r}.value});
182 end
183 node{i} = ClassSwitch(model, node_name{i}, csMatrix);
184 end
185 end
186 end
187 case 'Storage'
188 node{i} = Place(model, node_name{i});
189 case 'Enabling'
190 node{i} = Transition(model, node_name{i});
191 end
192end
193
194% create classes
195classes = {xDoc.userClass.ATTRIBUTE};
196% JMT uses higher priority value = higher priority, LINE uses lower value = higher priority
197% We need to invert priorities when importing from JMT
198maxPrio = 0;
199for r=1:length(classes)
200 if classes{r}.priority > maxPrio
201 maxPrio = classes{r}.priority;
202 end
203end
204for r=1:length(classes)
205 ref = findstring(node_name,classes{r}.referenceSource);
206 % Invert priority: JMT uses higher=higher, LINE uses lower=higher
207 linePrio = maxPrio - classes{r}.priority;
208 switch classes{r}.type
209 case JobClassType.toText(JobClassType.CLOSED)
210 jobclass{r} = ClosedClass(model, classes{r}.name, classes{r}.customers, node{ref}, linePrio);
211 case JobClassType.toText(JobClassType.OPEN)
212 % sink and source have been created before
213 jobclass{r} = OpenClass(model, classes{r}.name, linePrio);
214 if strcmpi(classes{r}.referenceSource,'StatelessClassSwitcher')
215 sourceIdx = cellisa(node,'Source');
216 node{sourceIdx}.setArrival(jobclass{r},Disabled.getInstance());
217 end
218 end
219end
220
221
222for i=1:length(node_name)
223 xsection_i{i} = {xsection{i}};
224 xsection_i{i} = xsection_i{i}{1}; % input, service, and output sections of node i
225 xsection_javaClass{i} = {xsection_i{i}.ATTRIBUTE};
226 switch xsection_javaClass{i}{1}.className % input section
227
228 case 'Storage'
229 node{i}.init();
230 if xsection_i{1,i}(1).parameter(1).value == -1
231 node{i}.setCapacity(Inf);
232 else
233 node{i}.setCapacity(xsection_i{1,i}(1).parameter(1).value);
234 end
235 if isa(xsection_i{1, i}(1).parameter(2).refClass,'cell')
236 nclasses = length(xsection_i{1, i}(1).parameter(2).refClass);
237 else
238 nclasses = 1;
239 end
240 for c=1:nclasses
241 if xsection_i{1, i}(1).parameter(2).subParameter(c).value == -1
242 node{i}.setClassCapacity(c, Inf);
243 else
244 node{i}.setClassCapacity(c, xsection_i{1, i}(1).parameter(2).subParameter(c).value);
245 end
246 switch xsection_i{1, i}(1).parameter(3).subParameter(c).value
247 case 'BAS blocking'
248 node{i}.setDropRule(c, DropStrategy.BAS);
249 case 'drop'
250 node{i}.setDropRule(c, DropStrategy.DROP);
251 case 'waiting queue'
252 node{i}.setDropRule(c, DropStrategy.WAITQ);
253 end
254 end
255 node{i}.setState(0);
256
257 case 'Enabling'
258 % Enabling Section
259 nmodes = length(xsection_i{1, i}(1).parameter(1).subParameter);
260 for m=1:nmodes
261 node{i}.setModeNames(m, xsection_i{1, i}(2).parameter(1).subParameter(m).value);
262 end
263 node{i}.init();
264 for m=1:nmodes
265 ninputs = length(xsection_i{1, i}(1).parameter(1).subParameter(m).subParameter.subParameter);
266 for j=1:ninputs
267 refClasses = xsection_i{1, i}(1).parameter(1).subParameter(m).subParameter.subParameter(j).subParameter(2).refClass;
268 if isa(refClasses,'cell')
269 nclasses = length(refClasses);
270 else
271 nclasses = 1;
272 end
273 nodeName = xsection_i{1, i}(1).parameter(1).subParameter(m).subParameter.subParameter(j).subParameter(1).value;
274 targetNode = model.getNodeByName(nodeName);
275 for k=1:nclasses
276 enable = xsection_i{1, i}(1).parameter(1).subParameter(m).subParameter.subParameter(j).subParameter(2).subParameter(k).value;
277 if enable == -1
278 node{i}.setEnablingConditions(m,k,targetNode,Inf);
279 else
280 node{i}.setEnablingConditions(m,k,targetNode,enable);
281 end
282 inhibit = xsection_i{1, i}(1).parameter(2).subParameter(m).subParameter.subParameter(j).subParameter(2).subParameter(k).value;
283 if inhibit == -1
284 node{i}.setInhibitingConditions(m,k,targetNode,Inf);
285 else
286 node{i}.setInhibitingConditions(m,k,targetNode,inhibit);
287 end
288 end
289 end
290 end
291 % Timing Section
292 for m=1:nmodes
293 numOfServers = xsection_i{1, i}(2).parameter(2).subParameter(m).value;
294 if numOfServers == -1
295 node{i}.setNumberOfServers(m, Inf);
296 else
297 node{i}.setNumberOfServers(m, numOfServers);
298 end
299 timingSt = xsection_i{1, i}(2).parameter(3).subParameter(m).ATTRIBUTE.classPath;
300 if strcmp(timingSt,'jmt.engine.NetStrategies.ServiceStrategies.ZeroServiceTimeStrategy')
301 node{i}.setTimingStrategy(m,TimingStrategy.IMMEDIATE);
302 else
303 node{i}.setTimingStrategy(m,TimingStrategy.TIMED);
304 distribution = xsection_i{1, i}(2).parameter(3).subParameter(m).subParameter(1).ATTRIBUTE.name;
305 lambda = xsection_i{1, i}(2).parameter(3).subParameter(m).subParameter(2).subParameter(1).value;
306 switch distribution
307 case 'Exponential'
308 node{i}.setDistribution(m,Exp(lambda));
309 case 'Erlang'
310 lambda1 = xsection_i{1, i}(2).parameter(3).subParameter(m).subParameter(2).subParameter(2).value;
311 node{i}.setDistribution(m,Erlang(lambda, lambda1));
312 case 'Hyperexponential'
313 lambda1 = xsection_i{1, i}(2).parameter(3).subParameter(m).subParameter(2).subParameter(2).value;
314 lambda2 = xsection_i{1, i}(2).parameter(3).subParameter(m).subParameter(2).subParameter(3).value;
315 node{i}.setDistribution(m,HyperExp(lambda, lambda1, lambda2));
316 case 'Coxian'
317 lambda1 = xsection_i{1, i}(2).parameter(3).subParameter(m).subParameter(2).subParameter(2).value;
318 lambda2 = xsection_i{1, i}(2).parameter(3).subParameter(m).subParameter(2).subParameter(3).value;
319 node{i}.setDistribution(m,Coxian([lambda, lambda1], [lambda2,1]));
320 case 'Deterministic'
321 node{i}.setDistribution(m,Det(lambda));
322 case 'Pareto'
323 lambda1 = xsection_i{1, i}(2).parameter(3).subParameter(m).subParameter(2).subParameter(2).value;
324 node{i}.setDistribution(m,Pareto(lambda, lambda1));
325 case 'Gamma'
326 lambda1 = xsection_i{1, i}(2).parameter(3).subParameter(m).subParameter(2).subParameter(2).value;
327 node{i}.setDistribution(m,Gamma(lambda, lambda1));
328 case 'Uniform'
329 lambda1 = xsection_i{1, i}(2).parameter(3).subParameter(m).subParameter(2).subParameter(2).value;
330 node{i}.setDistribution(m,Uniform(lambda, lambda1));
331 case 'Replayer'
332 node{i}.setDistribution(m,Replayer(lambda));
333 case 'Trace'
334 node{i}.setDistribution(m,Trace(lambda));
335 case 'Weibull'
336 lambda1 = xsection_i{1, i}(2).parameter(3).subParameter(m).subParameter(2).subParameter(2).value;
337 node{i}.setDistribution(m,Weibull(lambda1, lambda)); % scale and shape are inverted in the constructor
338 case 'Lognormal'
339 lambda1 = xsection_i{1, i}(2).parameter(3).subParameter(m).subParameter(2).subParameter(2).value;
340 node{i}.setDistribution(m,Lognormal(lambda, lambda1));
341 otherwise
342 error('The model includes an arrival distribution not supported by the model-to-model transformation from JMT.')
343 end
344 end
345 firingPriorities = xsection_i{1, i}(2).parameter(4).subParameter(m).value;
346 node{i}.setFiringPriorities(m, firingPriorities);
347 firingWeights = xsection_i{1, i}(2).parameter(5).subParameter(m).value;
348 node{i}.setFiringWeights(m, firingWeights);
349 end
350 % Firing Section
351 for m=1:nmodes
352 if isfield(xsection_i{1, i}(3).parameter(1).subParameter(m).subParameter,'CONTENT')
353 noutputs = 0;
354 else
355 noutputs = length(xsection_i{1, i}(3).parameter(1).subParameter(m).subParameter.subParameter);
356 end
357 for j=1:noutputs
358 refClasses = xsection_i{1, i}(3).parameter(1).subParameter(m).subParameter.subParameter(j).subParameter(2).refClass;
359 if isa(refClasses, 'cell')
360 nclasses = length(refClasses);
361 else
362 nclasses = 1;
363 end
364 nodeName = xsection_i{1, i}(3).parameter(1).subParameter(m).subParameter.subParameter(j).subParameter(1).value;
365 for k=1:nclasses
366 outcome = xsection_i{1, i}(3).parameter(1).subParameter(m).subParameter.subParameter(j).subParameter(2).subParameter(k).value;
367 if outcome == -1
368 node{i}.setFiringOutcome(m,k,nodeName,Inf);
369 else
370 node{i}.setFiringOutcome(m,k,nodeName,outcome);
371 end
372 end
373 end
374 end
375 end
376end
377
378schedparams = cell(1,length(node_name));
379% set service distributions
380for i=1:length(node_name)
381 if isa(node{i},'Source')
382 for r=1:length(classes)
383 xsection_par{i} = {xsection{i}.parameter};
384 xsection_i_par{i} = xsection_i{i}.parameter;
385 xsection_i_subpar{i} = {xsection_i_par{i}.subParameter};
386 xarv_statdistrib{i}{r}={xsection_i_subpar{i}{1}.subParameter};
387 if isempty(xarv_statdistrib{i}{r}{r})
388 node{i}.setArrival(jobclass{r}, Disabled.getInstance());
389 else
390 xarv_statdistrib{i}{r}={xarv_statdistrib{i}{r}{r}.ATTRIBUTE};
391 xarv{i} = {xsection_i{i}(1).parameter.subParameter};
392 xarv_sec{i} = {xarv{i}{1}.subParameter};
393 switch xarv_statdistrib{i}{r}{1}.name
394 case 'Exponential'
395 par={xarv_sec{i}{r}.subParameter}; par=par{2};
396 node{i}.setArrival(jobclass{r}, Exp(par.value));
397 case 'Erlang'
398 par={xarv_sec{i}{r}.subParameter}; par=par{2};
399 node{i}.setArrival(jobclass{r}, Erlang(par(1).value,par(2).value));
400 case 'Hyperexponential'
401 par={xarv_sec{i}{r}.subParameter}; par=par{2};
402 node{i}.setArrival(jobclass{r}, HyperExp(par(1).value,par(2).value,par(3).value));
403 case 'Coxian'
404 par={xarv_sec{i}{r}.subParameter}; par=par{2};
405 node{i}.setArrival(jobclass{r}, Coxian([par(1).value,par(2).value],[par(3).value,1]));
406 case 'Deterministic'
407 par={xarv_sec{i}{r}.subParameter}; par=par{2};
408 node{i}.setArrival(jobclass{r}, Det(par.value));
409 case 'Pareto'
410 par={xarv_sec{i}{r}.subParameter}; par=par{2};
411 node{i}.setArrival(jobclass{r}, Pareto(par(1).value, par(2).value));
412 case 'Weibull'
413 par={xarv_sec{i}{r}.subParameter}; par=par{2};
414 node{i}.setArrival(jobclass{r}, Weibull(par(1).value, par(2).value));
415 case 'Lognormal'
416 par={xarv_sec{i}{r}.subParameter}; par=par{2};
417 node{i}.setArrival(jobclass{r}, Lognormal(par(1).value, par(2).value));
418 case 'Gamma'
419 par={xarv_sec{i}{r}.subParameter}; par=par{2};
420 node{i}.setArrival(jobclass{r}, Gamma(par(1).value, par(2).value));
421 case 'Uniform'
422 par={xarv_sec{i}{r}.subParameter}; par=par{2};
423 node{i}.setArrival(jobclass{r}, Uniform(par(1).value, par(2).value));
424 case 'Replayer'
425 par={xarv_sec{i}{r}.subParameter}; par=par{2};
426 node{i}.setArrival(jobclass{r}, Replayer(par.value));
427 case 'Trace'
428 par={xarv_sec{i}{r}.subParameter}; par=par{2};
429 node{i}.setArrival(jobclass{r}, Trace(par.value));
430 case 'Burst (MMPP2)'
431 par={xarv_sec{i}{r}.subParameter}; par=par{2};
432 node{i}.setArrival(jobclass{r}, MMPP2(par(1).value,par(2).value,par(3).value,par(4).value));
433 case 'Burst (MAP)'
434 par={xarv_sec{i}{r}.subParameter}; par=par{2};
435 pars = {par(1).subParameter.subParameter};
436 D0 = [];
437 for c=1:length(pars)
438 D0 = [D0; pars{c}.value];
439 end
440 pars = {par(2).subParameter.subParameter};
441 D1 = [];
442 for c=1:length(pars)
443 D1 = [D1; pars{c}.value];
444 end
445 ax = MAP(D0,D1);
446 node{i}.setArrival(jobclass{r}, ax);
447 case 'Phase-Type'
448 par={xarv_sec{i}{r}.subParameter}; par=par{2};
449 alpha = [par(1).subParameter.subParameter.value];
450 pars = {par(2).subParameter.subParameter};
451 T = [];
452 for c=1:length(pars)
453 T = [T; pars{c}.value];
454 end
455 if any(any(tril(T,-1))>0) % not APH
456 line_warning(mfilename,'The input model uses a general PH distribution, which is not yet supported in LINE. Fitting the first three moments into an APH distribution.');
457 PH = {T,-T*ones(size(T,1),1)*alpha};
458 ax = APH.fitCentral(map_mean(PH), map_var(PH), map_skew(PH));
459 else % APH
460 ax = APH(alpha, T);
461 end
462 node{i}.setArrival(jobclass{r}, ax);
463 otherwise
464 line_error(mfilename,'The model includes an arrival distribution not supported by the model-to-model transformation from JMT.')
465 xarv_statdistrib{i}{r}{1}.name
466 node{i}.setArrival(jobclass{r}, Exp(1)); %TODO
467 end
468 end
469 end
470 elseif isa(node{i},'Queue') || isa(node{i},'Delay') || isa(node{i},'DelayStation')
471 if isempty(schedparams{i})
472 switch SchedStrategy.toId(strategy{i})
473 case {SchedStrategy.SEPT,SchedStrategy.LEPT}
474 schedparams{i} = NaN*ones(1,length(classes));
475 otherwise
476 schedparams{i} = ones(1,length(classes));
477 end
478 end
479 for r=1:length(classes)
480 switch xsection_i_type{i}{2}.className
481 case 'StatelessClassSwitcher'
482 % do nothing
483 continue
484 case 'Delay'
485 xsvc_sec{i} = {xsvc{i}{1}.subParameter};
486 otherwise
487 xsvc_sec{i} = {xsvc{i}{3}.subParameter};
488 end
489 if isempty(xsvc_sec{i}{r})
490 xsvc_statdistrib{i}{r}={struct('name','Disabled')};
491 else
492 xsvc_statdistrib{i}{r}={xsvc_sec{i}{r}.ATTRIBUTE};
493 end
494 para_ir = schedparams{i}(r);
495 switch xsvc_statdistrib{i}{r}{1}.name
496 case 'Disabled'
497 node{i}.setService(jobclass{r}, Disabled.getInstance());
498 case 'Replayer'
499 par={xsvc_sec{i}{r}.subParameter}; par=par{2};
500 node{i}.setService(jobclass{r}, Replayer(par.value), para_ir);
501 case 'Trace'
502 par={xsvc_sec{i}{r}.subParameter}; par=par{2};
503 node{i}.setService(jobclass{r}, Trace(par.value), para_ir);
504 case 'Exponential'
505 par={xsvc_sec{i}{r}.subParameter}; par=par{2};
506 node{i}.setService(jobclass{r}, Exp(par.value), para_ir);
507 case 'Erlang'
508 par={xsvc_sec{i}{r}.subParameter}; par=par{2};
509 node{i}.setService(jobclass{r}, Erlang(par(1).value,par(2).value), para_ir);
510 case 'Hyperexponential'
511 par={xsvc_sec{i}{r}.subParameter}; par=par{2};
512 node{i}.setService(jobclass{r}, HyperExp(par(1).value,par(2).value,par(3).value), para_ir);
513 case 'Coxian'
514 par={xsvc_sec{i}{r}.subParameter}; par=par{2};
515 node{i}.setService(jobclass{r}, Coxian([par(1).value,par(2).value],[par(3).value,1]), para_ir);
516 case 'Deterministic'
517 par={xsvc_sec{i}{r}.subParameter}; par=par{2};
518 node{i}.setService(jobclass{r}, Det(par.value));
519 case 'Pareto'
520 par={xsvc_sec{i}{r}.subParameter}; par=par{2};
521 node{i}.setService(jobclass{r}, Pareto(par(1).value, par(2).value));
522 case 'Weibull'
523 par={xsvc_sec{i}{r}.subParameter}; par=par{2};
524 node{i}.setService(jobclass{r}, Weibull(par(1).value, par(2).value));
525 case 'Lognormal'
526 par={xsvc_sec{i}{r}.subParameter}; par=par{2};
527 node{i}.setService(jobclass{r}, Lognormal(par(1).value, par(2).value));
528 case 'Gamma'
529 par={xsvc_sec{i}{r}.subParameter}; par=par{2};
530 node{i}.setService(jobclass{r}, Gamma(par(1).value, par(2).value));
531 case 'Burst (MMPP2)'
532 par={xsvc_sec{i}{r}.subParameter}; par=par{2};
533 node{i}.setService(jobclass{r}, MMPP2(par(1).value,par(2).value,par(3).value,par(4).value));
534 case 'Burst (MAP)'
535 par={xsvc_sec{i}{r}.subParameter}; par=par{2};
536 pars = {par(1).subParameter.subParameter};
537 D0 = [];
538 for c=1:length(pars)
539 D0 = [D0; pars{c}.value];
540 end
541 pars = {par(2).subParameter.subParameter};
542 D1 = [];
543 for c=1:length(pars)
544 D1 = [D1; pars{c}.value];
545 end
546 ax = MAP(D0,D1);
547 node{i}.setService(jobclass{r}, ax);
548 case 'Phase-Type'
549 par={xsvc_sec{i}{r}.subParameter}; par=par{2};
550 alpha = [par(1).subParameter.subParameter.value];
551 pars = {par(2).subParameter.subParameter};
552 T = [];
553 for c=1:length(pars)
554 T = [T; pars{c}.value];
555 end
556 if any(any(tril(T,-1))>0) % not APH
557 line_warning(mfilename,'The input model uses a general PH distribution, which is not yet supported in LINE. Fitting the first three moments into an APH distribution.');
558 PH = {T,-T*ones(size(T,1),1)*alpha};
559 ax = APH.fitCentral(map_mean(PH), map_var(PH), map_skew(PH));
560 else % APH
561 ax = APH(alpha, T);
562 end
563 node{i}.setService(jobclass{r}, ax);
564 case 'Uniform'
565 par={xsvc_sec{i}{r}.subParameter}; par=par{2};
566 node{i}.setService(jobclass{r}, Uniform(par(1).value, par(2).value));
567 otherwise
568 xsvc_statdistrib{i}{r}{1}.name
569 line_error(mfilename,'The model includes a service distribution not supported by the model-to-model transformation from JMT.')
570 xsvc_statdistrib{i}{r}{1}.name
571 node{i}.setService(jobclass{r}, Exp(1), para_ir); %TODO
572 end
573 end
574 for c=1:length(xsection_i_par_attr{i})
575 switch xsection_i_par_attr{i}{c}.name
576 case 'size'
577 node{i}.input.setSize(xsection_i_value{i}{c}); % buffer size
578 end
579 end
580 end
581end
582
583% create links
584C = zeros(length(node_name)); % connection matrix
585links = {xDoc.connection.ATTRIBUTE};
586for l=1:length(links)
587 source = findstring(orig_node_name,links{l}.source);
588 target = findstring(orig_node_name,links{l}.target);
589 % model.addLink(station{source},station{target});
590 C(source,target) = 1;
591end
592
593% assign routing probabilities
594P = zeros(length(node_name)*length(classes));
595for from=1:length(node_name)
596 for target=1:length(node_name)
597 if C(from,target)
598 model.addLink(node{from},node{target});
599 end
600 end
601end
602
603for from=1:length(node_name)
604 switch class(node{from})
605 case 'Place'
606 case 'Transition'
607 case 'Sink'
608 otherwise
609 for r=1:length(classes)
610 switch xrouting{from}{r}.name
611 case 'Random'
612 node{from}.setRouting(jobclass{r},RoutingStrategy.RAND);
613 % targets = find(C(from,:));
614 % if isa(jobclass{r},'Class')
615 % targets = setdiff(targets, [sink_idx, source_idx]);
616 % end
617 % for target = targets(:)'
618 % % node{from}.setProbRouting(jobclass{r}, node{target}, 1 / length(targets));
619 % P((from-1)*length(classes)+r, (target-1)*length(classes)+r) = 1 / length(targets);
620 % end
621 case 'Probabilities'
622 node{from}.setRouting(jobclass{r},RoutingStrategy.PROB);
623 xroutprobarray = {xsection_i{from}(3).parameter.subParameter.subParameter};
624 xroutprob = {xroutprobarray{r}.subParameter}; xroutprob = xroutprob{1};
625 xroutprobdest = {xroutprob.subParameter};
626 for j=1:length(xroutprobdest)
627 xprob={xroutprobdest{j}.value};
628 target = findstring(node_name,xprob{1});
629 prob = xprob{2};
630 node{from}.setProbRouting(jobclass{r}, node{target}, prob);
631 % P((from-1)*length(classes)+r, (target-1)*length(classes)+r) = prob;
632 end
633 case 'Power of k'
634 line_error(mfilename,'Power of k import not supported yet.')
635 case 'Round Robin'
636 node{from}.setRouting(jobclass{r},RoutingStrategy.RROBIN);
637 case 'Weighted Round Robin'
638 node{from}.setRouting(jobclass{r},RoutingStrategy.WRROBIN);
639 xroutprobarray = {xsection_i{from}(3).parameter.subParameter.subParameter};
640 xroutprob = {xroutprobarray{r}.subParameter}; xroutprob = xroutprob{1};
641 xroutprobdest = {xroutprob.subParameter};
642 for j=1:length(xroutprobdest)
643 xprob={xroutprobdest{j}.value};
644 target = findstring(node_name,xprob{1});
645 weight = xprob{2};
646 node{from}.setRouting(RoutingStrategy.WRROBIN, node{target}, jobclass{r}, weight);
647 end
648 case 'Join the Shortest Queue (JSQ)'
649 node{from}.setRouting(jobclass{r},RoutingStrategy.JSQ);
650 case 'Disabled'
651 node{from}.setRouting(jobclass{r},RoutingStrategy.DISABLED);
652 end
653 end
654 end
655end
656%model.link(P);
657%line_printf(['JMT2LINE parsing time: ',num2str(Ttot),' s\n']);
658
659if length(model.getIndexSourceStation)>1
660 txt = sprintf('LINE supports JMT models with at most a single source node. You can refactor your JMT model in several ways:\n - If you are mapping in JMT each class to a different source, this is not required. You can instead assign the same reference station to each class and configure class routing in the routing panel of the source node.\n - In more general cases, you may follow these three steps:\n (1) give a different name to each class of arrival, assigning these classes to a single source as reference station.\n (2) put a class-switch node after the source to switch the new classes into the original classes they were in the model with multiple sources.\n (3) configure the routing section of this class-switch node to set the same routing for the classes as they were in the original model.\n');
661 error(txt);
662end
663
664
665% Preload
666state = zeros(length(node),length(classes));
667if isfield(xDoc,'preload') && ~isempty(xDoc.preload.stationPopulations)
668 npreloadStates = length(xDoc.preload.stationPopulations);
669 for st=1:npreloadStates
670 nodeName = xDoc.preload.stationPopulations(st).ATTRIBUTE.stationName;
671 ind = model.getNodeIndex(nodeName);
672 for r=1:length(xDoc.preload.stationPopulations(st).classPopulation)
673 c = model.getClassIndex(xDoc.preload.stationPopulations(st).classPopulation(r).ATTRIBUTE.refClass);
674 state(ind,c) = xDoc.preload.stationPopulations(st).classPopulation(r).ATTRIBUTE.population;
675 end
676 if isa(node{ind},'Place')
677 %node{ind}.setState(state(ind,:));
678 if length(classes)>1
679 line_error(mfilename,'Import failed: Colored Petri net models are not yet supported in LINE.\n');
680 end
681 end
682 end
683end
684try
685 model.initFromMarginal(state);
686catch
687 line_warning(mfilename,'Import failed to automatically initialize the model.\n');
688end
689Ttot=toc(T0);
690end