1 | package desmoj.core.simulator; |
2 | |
3 | import java.awt.event.WindowAdapter; |
4 | import java.awt.event.WindowEvent; |
5 | import java.io.File; |
6 | import java.util.ArrayList; |
7 | import java.util.List; |
8 | import java.util.concurrent.TimeUnit; |
9 | |
10 | import javax.swing.JFrame; |
11 | |
12 | import desmoj.core.dist.DistributionManager; |
13 | import desmoj.core.exception.DESMOJException; |
14 | import desmoj.core.report.DebugNote; |
15 | import desmoj.core.report.ErrorMessage; |
16 | import desmoj.core.report.FileOutput; |
17 | import desmoj.core.report.Message; |
18 | import desmoj.core.report.MessageDistributor; |
19 | import desmoj.core.report.MessageReceiver; |
20 | import desmoj.core.report.OutputType; |
21 | import desmoj.core.report.OutputTypeEndToExport; |
22 | import desmoj.core.report.Reporter; |
23 | import desmoj.core.report.TraceNote; |
24 | |
25 | /** |
26 | * Experiment is the class that provides the infrastructure for running the |
27 | * simulation of a model. It contains all data structures necessary to simulate |
28 | * the model and takes care of all necessary output. To actually run an |
29 | * experiment, a new instance of the experiment class and a new instance of the |
30 | * desired model have to be created. To link both instances, call the |
31 | * <code>connectToExperiment(Experiment e)</code> method of the model instance |
32 | * and pass the new experiment as a parameter. |
33 | * |
34 | * @version DESMO-J, Ver. 2.3.3 copyright (c) 2011 |
35 | * @author Tim Lechler |
36 | * @author modified by Soenke Claassen, Ruth Meyer, Nicolas Knaak, Gunnar |
37 | * Kiesel,Felix Klueckmann |
38 | * |
39 | * Licensed under the Apache License, Version 2.0 (the "License"); |
40 | * you may not use this file except in compliance with the License. You |
41 | * may obtain a copy of the License at |
42 | * http://www.apache.org/licenses/LICENSE-2.0 |
43 | * |
44 | * Unless required by applicable law or agreed to in writing, software |
45 | * distributed under the License is distributed on an "AS IS" |
46 | * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
47 | * or implied. See the License for the specific language governing |
48 | * permissions and limitations under the License. |
49 | * |
50 | * @version DESMO-J, Ver. 2.3.3 copyright (c) 2011 |
51 | * @modifier new Example Variable _traceOutput, _reportOutput for Outputclasscollection |
52 | * new class constructors |
53 | * Experiment(String , String , ArrayList<String> , ArrayList<String> ,ArrayList<String> , ArrayList<String> ) and |
54 | * Experiment(String , String , TimeUnit ,TimeUnit , TimeFormatter ,ArrayList<String> , |
55 | * ArrayList<String> ,ArrayList<String> ,ArrayList<String> ) |
56 | * @author Xiufeng Li |
57 | */ |
58 | public class Experiment extends NamedObject { |
59 | |
60 | /** |
61 | * The experiment's name catalog for ensuring uniqueness of simulation |
62 | * object names within a single experiment. |
63 | */ |
64 | private NameCatalog _nameCatalog = new NameCatalog(); |
65 | |
66 | /** |
67 | * The default report output |
68 | */ |
69 | public static final String DEFAULT_REPORT_OUTPUT_TYPE = "desmoj.core.report.HTMLReportOutput"; |
70 | |
71 | /** |
72 | * The default trace output |
73 | */ |
74 | public static final String DEFAULT_TRACE_OUTPUT_TYPE = "desmoj.core.report.HTMLTraceOutput"; |
75 | |
76 | /** |
77 | * The default error output |
78 | */ |
79 | public static final String DEFAULT_ERROR_OUTPUT_TYPE = "desmoj.core.report.HTMLErrorOutput"; |
80 | |
81 | /** |
82 | * The default debug output |
83 | */ |
84 | public static final String DEFAULT_DEBUG_OUTPUT_TYPE = "desmoj.core.report.HTMLDebugOutput"; |
85 | |
86 | /** |
87 | * Status of an Experiment just created without any accessories created yet. |
88 | */ |
89 | public static final int NOT_INITIALIZED = -3; |
90 | |
91 | /** |
92 | * Status of an Experiment instantiated with all needed accessories |
93 | * available. |
94 | */ |
95 | public static final int INITIALIZED = -2; |
96 | |
97 | /** |
98 | * Status of an Experiment connected to a Model and ready to be started. |
99 | */ |
100 | public static final int CONNECTED = -1; |
101 | |
102 | /** |
103 | * Status of an Experiment being started. Only if an Experiment is |
104 | */ |
105 | public static final int STARTED = 0; |
106 | |
107 | /** |
108 | * Status of an Experiment stopped after having run. |
109 | */ |
110 | public static final int STOPPED = 1; |
111 | |
112 | /** |
113 | * Status of an Experiment currently running the simulation. |
114 | */ |
115 | public static final int RUNNING = 2; |
116 | |
117 | /** |
118 | * Status of an Experiment finished and to be cleared. |
119 | */ |
120 | public static final int ABORTED = 3; |
121 | |
122 | /** |
123 | * The last suffix used with filenames when creating multiple batch runs of |
124 | * an experiment. |
125 | */ |
126 | private static int lastSuffix; |
127 | |
128 | /** |
129 | * The class reference to messages of type desmoj.core.report.TraceNote |
130 | */ |
131 | static Class<desmoj.core.report.TraceNote> tracenote; |
132 | |
133 | /** |
134 | * The class reference to messages of type desmoj.core.report.DebugNote |
135 | */ |
136 | static Class<desmoj.core.report.DebugNote> debugnote; |
137 | |
138 | /** |
139 | * The class reference to messages of type desmoj.core.report.ErrorMessage |
140 | */ |
141 | static Class<desmoj.core.report.ErrorMessage> errormessage; |
142 | |
143 | /** |
144 | * The class reference to messages of type desmoj.core.report.Reporter |
145 | */ |
146 | static Class<desmoj.core.report.Reporter> reporter; |
147 | |
148 | /** |
149 | * Flag indicating to suppress notifications like 'experiment started'. |
150 | */ |
151 | private boolean _silent; |
152 | |
153 | /** |
154 | * The description of this Experiment |
155 | */ |
156 | private String _description = null; |
157 | |
158 | /** |
159 | * Flag indicating if the simulation is running. |
160 | */ |
161 | private int _status; |
162 | |
163 | /** |
164 | * The model to be run by this experiment. |
165 | */ |
166 | private Model _client; |
167 | |
168 | /** |
169 | * The scheduler used for this experiment. |
170 | */ |
171 | protected Scheduler clientScheduler; |
172 | |
173 | /** |
174 | * The distribution manager for the model's distributions. |
175 | */ |
176 | private DistributionManager _distMan; |
177 | |
178 | /** |
179 | * The message manager for the model's messages. |
180 | */ |
181 | private MessageDistributor _messMan; |
182 | |
183 | /** |
184 | * The ThreadGroup for this Experiment. |
185 | */ |
186 | private ThreadGroup _expThreads; |
187 | |
188 | /** |
189 | * The list to register all OutputType objects to close them after finishing |
190 | * the Experiment. |
191 | */ |
192 | private java.util.ArrayList<OutputType> _registryOutputType; |
193 | |
194 | /** |
195 | * The list to register all FileOutput objects to close them after finishing |
196 | * the Experiment. |
197 | */ |
198 | private java.util.ArrayList<FileOutput> _registryFileOutput; |
199 | |
200 | /** |
201 | * The resource database storing all resource allocations and requests. Also |
202 | * needed to detect deadlocks. |
203 | */ |
204 | private ResourceDB _resDB; |
205 | |
206 | /** |
207 | * The TimeInstant when the experiment is supposed to stop. Is initially |
208 | * <code>null</code> and will be set only if the user provides a time limit. |
209 | */ |
210 | private TimeInstant _stopTime = null; |
211 | |
212 | /** |
213 | * The event to stop the experiment. Is initially <code>null</code> and will |
214 | * be set only if the user provides a time limit. |
215 | */ |
216 | private ExternalEventStop _stopTimeEvent = null; |
217 | |
218 | /** |
219 | * A list of <code>Condition</code>s which cause the experiment to stop. The |
220 | * user has to implement the <code>check()</code> method of the |
221 | * <code>Condition</code>s in order to effectively stop an experiment. |
222 | */ |
223 | private List<ModelCondition> _stopConditions; |
224 | |
225 | /** |
226 | * Flag indicating whether a progressbar for this experiment should be |
227 | * displayed or not. |
228 | */ |
229 | private boolean _showProgressBar; |
230 | |
231 | /** |
232 | * Specifies an output path for the report files (Modification by Nicolas |
233 | * Knaak, 02/2001) |
234 | */ |
235 | private String _pathName; |
236 | |
237 | /** |
238 | * Delay between steps of the scheduler in milliseconds. Necessary for |
239 | * online observation of experiments in FAMOS. (Modification by Nicolas |
240 | * Knaak, 07/2001) |
241 | */ |
242 | private long _delayInMillis = 0; |
243 | |
244 | /** |
245 | * The real time (wallclock time) start time of the simulation run. |
246 | * (Modification by Felix Klueckmann, 05/2009) |
247 | */ |
248 | private long _realTimeStartTime; |
249 | |
250 | /** |
251 | * The output types of the debug channel. |
252 | */ |
253 | private ArrayList<OutputType> _debugOutput; |
254 | |
255 | /** |
256 | * The output types of the report channel. |
257 | */ |
258 | private ArrayList<OutputType> _reportOutput; |
259 | |
260 | /** |
261 | * The output types of the error channel. |
262 | */ |
263 | private ArrayList<OutputType> _errorOutput; |
264 | |
265 | /** |
266 | * The output types of the trance channel. |
267 | */ |
268 | private ArrayList<OutputType> _traceOutput; |
269 | |
270 | /** |
271 | * Constructs a new Experiment with a given name. |
272 | * Data channel output (report, error, debug, trace) will either be |
273 | * written to HTML files in the current directory. |
274 | * Epsilon (granularity of simulation) defaults to a microsecond, |
275 | * reference time (default time unit) to a second. |
276 | * |
277 | * @param name |
278 | * String : The name of the experiment determining the |
279 | * outputfile's names, too. So please avoid characters that your |
280 | * local filesystem does not support in filenames. |
281 | */ |
282 | public Experiment(String name) { |
283 | this(name, true); |
284 | } |
285 | |
286 | /** |
287 | * Constructs a new Experiment with the given parameters. Experiment name can be specified. |
288 | * Data channel output (report, error, debug, trace) will either be |
289 | * suppressed or written to HTML files in the current directory. |
290 | * Epsilon (granularity of simulation) defaults to a microsecond, |
291 | * reference time (default time unit) to a second. |
292 | * |
293 | * @param name |
294 | * String : The name of the experiment determining the |
295 | * outputfile's names, too. So please avoid characters that your |
296 | * local filesystem does not support in filenames. |
297 | * @param output |
298 | * boolean : This flag indicates if the experiment should write |
299 | * output files in the default format (HTML) or no output files |
300 | * at all. |
301 | */ |
302 | public Experiment(String name, boolean output) { |
303 | this(name, ".", TimeUnit.MICROSECONDS, TimeUnit.SECONDS, null, |
304 | output ? DEFAULT_REPORT_OUTPUT_TYPE : null, |
305 | output ? DEFAULT_TRACE_OUTPUT_TYPE : null, |
306 | output ? DEFAULT_ERROR_OUTPUT_TYPE : null, |
307 | output ? DEFAULT_DEBUG_OUTPUT_TYPE : null); // call most special |
308 | // constructor |
309 | } |
310 | |
311 | /** |
312 | * Constructs a new Experiment with the given parameters. Experiment name and output path |
313 | * can be specified. Data channel output (report, error, debug, trace) will either be |
314 | * written to HTML files, epsilon (granularity of simulation) defaults to a microsecond, |
315 | * reference time (default time unit) to a second. |
316 | * |
317 | * @param name |
318 | * String : The name of the experiment determining the |
319 | * outputfile's names, too. So please avoid characters that your |
320 | * local filesystem does not support in filenames. |
321 | * @param pathName |
322 | * java.lang.String : The output path for report files |
323 | */ |
324 | public Experiment(String name, String pathName) { |
325 | |
326 | this(name, pathName, DEFAULT_REPORT_OUTPUT_TYPE, |
327 | DEFAULT_TRACE_OUTPUT_TYPE, DEFAULT_ERROR_OUTPUT_TYPE, |
328 | DEFAULT_DEBUG_OUTPUT_TYPE); |
329 | // call more special constructor |
330 | |
331 | } |
332 | |
333 | /** |
334 | * Constructs a new Experiment with the given parameters. This is a shortcut |
335 | * constructor. Parameters for the name, the granularity(epsilon), the |
336 | * reference time unit and a time formatter are needed. All other possible |
337 | * settings are set to default values. These settings for an experiment |
338 | * without special ExperimentOptions are: |
339 | * <ol> |
340 | * <li>seed = 979 : The initial seed setting for the seed-generator</li> |
341 | * </ol> |
342 | * The default stop condition for this experiment will never interfere, |
343 | * always returning false. |
344 | * |
345 | * @param name |
346 | * String : The name of the experiment determining the |
347 | * outputfile's names, too. So please avoid characters that your |
348 | * local filesystem does not support in filenames. |
349 | * @param epsilon |
350 | * java.util.concurrent.TimeUnit: The granularity of simulation |
351 | * time. |
352 | * @param referenceUnit |
353 | * java.util.concurrent.TimeUnit : In statements without an |
354 | * explicit declaration of a TimeUnit the reference unit is used. |
355 | * @param formatter |
356 | * desmoj.core.simulator.TimeFormatter: Defines how time values |
357 | * will be formatted in the output files. |
358 | * |
359 | * @see java.util.concurrent.TimeUnit |
360 | */ |
361 | public Experiment(String name, TimeUnit epsilon, TimeUnit referenceUnit, |
362 | TimeFormatter formatter) { |
363 | // call most special constructor |
364 | this(name, ".", epsilon, referenceUnit, formatter, |
365 | DEFAULT_REPORT_OUTPUT_TYPE, DEFAULT_TRACE_OUTPUT_TYPE, |
366 | DEFAULT_ERROR_OUTPUT_TYPE, DEFAULT_DEBUG_OUTPUT_TYPE); |
367 | |
368 | } |
369 | |
370 | /** |
371 | * Constructs a new Experiment with the given parameters. Experiment name, output path |
372 | * and a single file type per output channel can be specified. |
373 | * Epsilon (granularity of simulation) defaults to a microsecond, |
374 | * reference time (default time unit) to a second. |
375 | * |
376 | * @param name |
377 | * String : The name of the experiment determining the |
378 | * outputfile's names, too. So please avoid characters that your |
379 | * local filesystem does not support in filenames. |
380 | * @param pathName |
381 | * java.lang.String : The output path for report files |
382 | * @see desmoj.core.simulator.Units |
383 | * @param reportOutputType |
384 | * @param traceOutputType |
385 | * @param errorOutputType |
386 | * @param debugOutputType |
387 | */ |
388 | public Experiment(String name, String pathName, String reportOutputType, |
389 | String traceOutputType, String errorOutputType, |
390 | String debugOutputType) { |
391 | this(name, pathName, TimeUnit.MICROSECONDS, TimeUnit.SECONDS, null, |
392 | reportOutputType, traceOutputType, errorOutputType, |
393 | debugOutputType); |
394 | } |
395 | |
396 | /** |
397 | * Constructs a new Experiment with the given parameters. Experiment name, output path, epsilon, reference time unit, time format, |
398 | * can be specified. Same holds for file output channels, though this constructor assumes a single file type per output channel. |
399 | * |
400 | * @param name |
401 | * String : The name of the experiment determining the |
402 | * outputfile's names, too. So please avoid characters that your |
403 | * local filesystem does not support in filenames. |
404 | * @param pathName |
405 | * java.lang.String : The output path for report files |
406 | * @param epsilon |
407 | * java.util.concurrent.TimeUnit: The granularity of simulation |
408 | * time. |
409 | * @param referenceUnit |
410 | * java.util.concurrent.TimeUnit : In statements without an |
411 | * explicit declaration of a TimeUnit the reference unit is used. |
412 | * @param formatter |
413 | * desmoj.core.simulator.TimeFormatter: Defines how time values |
414 | * will be formatted in the output files. |
415 | * |
416 | * @see java.util.concurrent.TimeUnit |
417 | */ |
418 | public Experiment(String name, String pathName, TimeUnit epsilon, |
419 | TimeUnit referenceUnit, TimeFormatter formatter, |
420 | String reportOutputType, String traceOutputType, |
421 | String errorOutputType, String debugOutputType) { |
422 | super(name); // create a NamedObject with an attitude ;-) |
423 | |
424 | ArrayList<String> reportOutputs = new ArrayList<String>(); if (reportOutputType!=null) reportOutputs.add(reportOutputType); |
425 | ArrayList<String> traceOutputs = new ArrayList<String>(); if (traceOutputType!=null) traceOutputs.add(traceOutputType); |
426 | ArrayList<String> errorOutputs = new ArrayList<String>(); if (errorOutputType!=null) errorOutputs.add(errorOutputType); |
427 | ArrayList<String> debugOutputs = new ArrayList<String>(); if (debugOutputType!=null) debugOutputs.add(debugOutputType); |
428 | |
429 | setupExperiment(name, pathName, epsilon, referenceUnit, formatter, reportOutputs, traceOutputs, errorOutputs, debugOutputs); |
430 | } |
431 | |
432 | /** |
433 | * Constructs a new Experiment with the given parameters. This is the most |
434 | * flexible constructor. Experiment name, output path, epsilon, reference time unit, time format, |
435 | * and multiple file types per output channel can be specified. |
436 | * |
437 | * @param name |
438 | * String : The name of the experiment determining the |
439 | * outputfile's names, too. So please avoid characters that your |
440 | * local filesystem does not support in filenames. |
441 | * @param outputPath |
442 | * java.lang.String : The output path for report files |
443 | * @param epsilon |
444 | * java.util.concurrent.TimeUnit: The granularity of simulation |
445 | * time. |
446 | * @param referenceUnit |
447 | * java.util.concurrent.TimeUnit : In statements without an |
448 | * explicit declaration of a TimeUnit the reference unit is used. |
449 | * @param formatter |
450 | * desmoj.core.simulator.TimeFormatter: Defines how time values |
451 | * will be formatted in the output files. |
452 | * |
453 | * @see java.util.concurrent.TimeUnit |
454 | */ |
455 | public Experiment(String name, String outputPath, TimeUnit epsilon, |
456 | TimeUnit referenceUnit, TimeFormatter formatter, |
457 | ArrayList<String> reportOutputs, ArrayList<String> traceOutputs, |
458 | ArrayList<String> errorOutputs, ArrayList<String> debugOutputs) |
459 | { |
460 | super(name); |
461 | setupExperiment(name, outputPath, epsilon, referenceUnit, formatter, reportOutputs, traceOutputs, errorOutputs, debugOutputs); |
462 | } |
463 | /** |
464 | * Constructs a new Experiment with the given parameters. Experiment name, output path |
465 | * and a multiple file type per output channel can be specified. |
466 | * Epsilon (granularity of simulation) defaults to a microsecond, |
467 | * reference time (default time unit) to a second. |
468 | * |
469 | * @param name |
470 | * String : The name of the experiment determining the |
471 | * outputfile's names, too. So please avoid characters that your |
472 | * local filesystem does not support in filenames. |
473 | * @param outputPath |
474 | * java.lang.String : The output path for report files |
475 | * @see desmoj.core.simulator.Units |
476 | */ |
477 | public Experiment(String name, String outputPath, |
478 | ArrayList<String> reportOutputs, ArrayList<String> traceOutputs, |
479 | ArrayList<String> errorOutputs, ArrayList<String> debugOutputs) { |
480 | this(name, outputPath, TimeUnit.MICROSECONDS, TimeUnit.SECONDS, null, |
481 | reportOutputs, traceOutputs, errorOutputs, |
482 | debugOutputs); |
483 | } |
484 | |
485 | |
486 | /** |
487 | * Private helper method to initialize the experiment; should be called |
488 | * from all constructors. |
489 | * |
490 | * @param name |
491 | * String : The name of the experiment determining the |
492 | * outputfile's names, too. So please avoid characters that your |
493 | * local filesystem does not support in filenames. |
494 | * @param outputPath |
495 | * java.lang.String : The output path for report files |
496 | * @param epsilon |
497 | * java.util.concurrent.TimeUnit: The granularity of simulation |
498 | * time. |
499 | * @param referenceUnit |
500 | * java.util.concurrent.TimeUnit : In statements without an |
501 | * explicit declaration of a TimeUnit the reference unit is used. |
502 | * @param formatter |
503 | * desmoj.core.simulator.TimeFormatter: Defines how time values |
504 | * will be formatted in the output files. |
505 | * |
506 | * @see java.util.concurrent.TimeUnit |
507 | */ |
508 | private void setupExperiment(String name, String outputPath, TimeUnit epsilon, |
509 | TimeUnit referenceUnit, TimeFormatter formatter, |
510 | ArrayList<String> reportOutputs, ArrayList<String> traceOutputs, |
511 | ArrayList<String> errorOutputs, ArrayList<String> debugOutputs) |
512 | { |
513 | // initialize variables |
514 | _traceOutput = new ArrayList<OutputType>(); |
515 | _debugOutput = new ArrayList<OutputType>(); |
516 | _errorOutput = new ArrayList<OutputType>(); |
517 | _reportOutput = new ArrayList<OutputType>(); |
518 | _status = NOT_INITIALIZED; |
519 | _stopConditions = new ArrayList<ModelCondition>(); // empty, i.e. no Stopper |
520 | // can be set at |
521 | // instantiation time |
522 | _expThreads = new ThreadGroup(name); |
523 | _registryFileOutput = new ArrayList<FileOutput>(); |
524 | _registryOutputType = new ArrayList<OutputType>(); |
525 | lastSuffix = 0; // no batches have run so far ;-) |
526 | _showProgressBar = true; // display a progress bar for this experiment |
527 | _silent = false; // notify the user about what is going on |
528 | |
529 | // Check and set output path |
530 | // if (pathName == null |
531 | // || (pathName != null && (pathName.isEmpty() || pathName |
532 | // .equals(".")))) |
533 | // this.pathName = System.getProperty("user.dir", "."); |
534 | // else |
535 | this._pathName = outputPath; |
536 | |
537 | // set class variables for basic messagetypes |
538 | try |
539 | { |
540 | tracenote = (Class<TraceNote>) Class |
541 | .forName("desmoj.core.report.TraceNote"); |
542 | debugnote = (Class<DebugNote>) Class |
543 | .forName("desmoj.core.report.DebugNote"); |
544 | errormessage = (Class<ErrorMessage>) Class |
545 | .forName("desmoj.core.report.ErrorMessage"); |
546 | reporter = (Class<Reporter>) Class |
547 | .forName("desmoj.core.report.Reporter"); |
548 | } catch (ClassNotFoundException cnfEx) |
549 | { |
550 | System.err.println("Can not create Experiment!"); |
551 | System.err.println("Constructor of desmoj.core.Experiment."); |
552 | System.err.println("Classes are probably not installed correctly."); |
553 | System.err.println("Check your CLASSPATH setting."); |
554 | System.err.println("Exception caught : " + cnfEx); |
555 | } |
556 | |
557 | // create output system first |
558 | _messMan = new MessageDistributor(); |
559 | |
560 | // create and register the debug output |
561 | for (String debugOutputType : debugOutputs) |
562 | { |
563 | try |
564 | { |
565 | Class<OutputType> debugOType = (Class<OutputType>) Class |
566 | .forName((debugOutputType != null) ? debugOutputType |
567 | : DEFAULT_DEBUG_OUTPUT_TYPE); |
568 | OutputType dbg = debugOType.newInstance(); |
569 | _debugOutput.add(dbg); |
570 | if (debugOutputType != null) |
571 | dbg.open(_pathName, name); |
572 | _messMan.register(dbg, debugnote); |
573 | _messMan.switchOff(debugnote); |
574 | register(dbg); |
575 | } catch (Exception e) |
576 | { |
577 | System.err.println(e.toString()); |
578 | } |
579 | } |
580 | |
581 | // create and register the report output |
582 | for (String reportOutputType : reportOutputs) |
583 | { |
584 | try |
585 | { |
586 | Class<OutputType> reportOType = (Class<OutputType>) Class |
587 | .forName((reportOutputType != null) ? reportOutputType |
588 | : DEFAULT_REPORT_OUTPUT_TYPE); |
589 | OutputType rpt = reportOType.newInstance(); |
590 | _reportOutput.add(rpt); |
591 | if (reportOutputType != null) |
592 | rpt.open(_pathName, name); |
593 | _messMan.register(rpt, reporter); |
594 | register(rpt); |
595 | } catch (Exception e) |
596 | { |
597 | System.err.println(e.toString()); |
598 | } |
599 | } |
600 | |
601 | // create and register the error output |
602 | for (String errorOutputType : errorOutputs) |
603 | { |
604 | try |
605 | { |
606 | Class<OutputType> errorOType = (Class<OutputType>) Class |
607 | .forName((errorOutputType != null) ? errorOutputType |
608 | : DEFAULT_ERROR_OUTPUT_TYPE); |
609 | OutputType err = errorOType.newInstance(); |
610 | _errorOutput.add(err); |
611 | // err.setTimeFloats(timeFloats); |
612 | if (errorOutputType != null) |
613 | err.open(_pathName, name); |
614 | _messMan.register(err, errormessage); |
615 | register(err); |
616 | } catch (Exception e) |
617 | { |
618 | System.err.println(e.toString()); |
619 | } |
620 | } |
621 | // create and register the trace output |
622 | for (String traceOutputType : traceOutputs) |
623 | { |
624 | try |
625 | { |
626 | |
627 | Class<OutputType> traceOType = (Class<OutputType>) Class |
628 | .forName((traceOutputType != null) ? traceOutputType |
629 | : DEFAULT_TRACE_OUTPUT_TYPE); |
630 | OutputType trc = traceOType.newInstance(); |
631 | _traceOutput.add(trc); |
632 | if (traceOutputType != null) |
633 | trc.open(_pathName, name); |
634 | _messMan.register(trc, tracenote); |
635 | _messMan.switchOff(tracenote); |
636 | register(trc); |
637 | } catch (Exception e) |
638 | { |
639 | System.err.println(e.toString()); |
640 | } |
641 | } |
642 | |
643 | // create the distributionmanager to register distributions at |
644 | _distMan = new DistributionManager(name, 979); |
645 | |
646 | // now create the simulation runtime accessories |
647 | _client = null; // no object connected |
648 | |
649 | // check for null reference |
650 | if (epsilon == null) |
651 | { |
652 | // set to default unit |
653 | epsilon = TimeUnit.MICROSECONDS; |
654 | } |
655 | if (referenceUnit == null) |
656 | { |
657 | // set to default unit |
658 | referenceUnit = TimeUnit.SECONDS; |
659 | } |
660 | // interchange epsilon and reference unit if the reference unit has a |
661 | // finer granularity than epsilon |
662 | if (referenceUnit.compareTo(epsilon) < 0) |
663 | { |
664 | TimeUnit buffer = referenceUnit; |
665 | referenceUnit = epsilon; |
666 | epsilon = buffer; |
667 | } |
668 | // set epsilon and referenceUnit |
669 | TimeOperations.setEpsilon(epsilon); |
670 | TimeOperations.setReferenceUnit(referenceUnit); |
671 | |
672 | // check for null reference |
673 | if (formatter == null) |
674 | { |
675 | formatter = new SingleUnitTimeFormatter(referenceUnit, epsilon, 4, |
676 | false); |
677 | } |
678 | TimeOperations.setTimeFormatter(formatter); |
679 | |
680 | // building the scheduler: prepare event list... |
681 | // (for efficiency reasons, we use the TreeList-basd implementation) |
682 | EventList eventList = new EventTreeList(); |
683 | |
684 | // create the scheduler (and clock) |
685 | clientScheduler = createScheduler(name, eventList); |
686 | |
687 | // create a resource database and tell it that it belongs to this |
688 | // experiment |
689 | _resDB = new ResourceDB(this); |
690 | |
691 | // set status to first valid value - initialized, but not connected |
692 | _status = INITIALIZED; |
693 | } |
694 | |
695 | /** |
696 | * Creates a scheduler for this experiment. |
697 | * |
698 | * @param name |
699 | * experiment name |
700 | * @return a new scheduler |
701 | */ |
702 | protected Scheduler createScheduler(String name, EventList evl) { |
703 | Scheduler s = new Scheduler(this, name, evl); |
704 | return s; |
705 | } |
706 | |
707 | /** |
708 | * Adds a messagereceiver for debugnotes to the experiment. Whenever a model |
709 | * produces a message of that type, it will also be sent to the given |
710 | * messagereceiver for further processing. Note that the given receiver must |
711 | * be capable of handling debugnotes. |
712 | * |
713 | * @param trcRec |
714 | * desmoj.report.MessageReceiver : The new messagereceiver for |
715 | * the given type of messages |
716 | */ |
717 | public void addDebugReceiver(MessageReceiver trcRec) { |
718 | |
719 | if (trcRec == null) { |
720 | sendWarning("Can not add receiver to experiment! Command ignored.", |
721 | "Experiment '" + getName() |
722 | + "', method 'void addDebugReceiver(" |
723 | + "MessageReceiver trcRec)'", |
724 | "The parameter 'trc' passed was a null reference.", |
725 | "Make sure to construct a valid MessageReciever before adding it to " |
726 | + "the experiment's messaging system."); |
727 | return; // do nothing |
728 | } |
729 | |
730 | _messMan.register(trcRec, debugnote); |
731 | |
732 | } |
733 | |
734 | /** |
735 | * Adds a messagereceiver for error messages to the experiment. Whenever a |
736 | * model produces a message of that type, it will also be sent to the given |
737 | * messagereceiver for further processing. Note that the given receiver must |
738 | * be capable of handling messagereceiver. |
739 | * |
740 | * @param trcRec |
741 | * desmoj.report.MessageReceiver : The new messagereceiver for |
742 | * the given type of messages |
743 | */ |
744 | public void addErrorReceiver(MessageReceiver trcRec) { |
745 | |
746 | if (trcRec == null) { |
747 | sendWarning("Can not add receiver to experiment! Command ignored.", |
748 | "Experiment '" + getName() |
749 | + "', method 'void addErrorReceiver(" |
750 | + "MessageReceiver trcRec)'", |
751 | "The parameter 'trc' passed was a null reference.", |
752 | "Make sure to construct a valid MessageReciever before adding it to " |
753 | + "the experiment's messaging system."); |
754 | return; // do nothing |
755 | } |
756 | |
757 | _messMan.register(trcRec, errormessage); |
758 | |
759 | } |
760 | |
761 | /** |
762 | * Returns the experiments name catalog for ensuring unique names of |
763 | * simulation objects within a single experiment. |
764 | */ |
765 | NameCatalog getNameCatalog() { |
766 | return _nameCatalog; |
767 | } |
768 | |
769 | /** |
770 | * Adds a messagereceiver for the given subtype of message to the |
771 | * experiment. Whenever a model produces a message of that type, it will |
772 | * also be sent to the given messagereceiver for further processing. |
773 | * |
774 | * @param trcRec |
775 | * desmoj.report.MessageReceiver : The new messagereceiver for |
776 | * the given type of messages |
777 | * @param messageType |
778 | * Class : The type of message to be sent to the given |
779 | * messagereceiver |
780 | */ |
781 | public void addReceiver(MessageReceiver trcRec, Class<?> messageType) { |
782 | |
783 | if (trcRec == null) { |
784 | sendWarning("Can not add receiver to experiment! Command ignored.", |
785 | "Experiment '" + getName() |
786 | + "', method 'void addReceiver(MessageReceiver " |
787 | + "trcRec, Class messageType)'", |
788 | "The parameter 'trc' passed was a null reference.", |
789 | "Make sure to construct a valid MessageReciever before adding it to " |
790 | + "the experiment's messaging system."); |
791 | return; // do nothing |
792 | } |
793 | |
794 | if (messageType == null) { // again these damned null values |
795 | sendWarning("Can not add receiver to experiment! Command ignored.", |
796 | "Experiment '" + getName() |
797 | + "', method 'void addReceiver(MessageReceiver " |
798 | + "trcRec, Class messageType)'", |
799 | "The parameter 'messageType' passed was a null reference.", |
800 | "Make sure to construct a valid Class object before adding it to " |
801 | + "the experiment's messaging system."); |
802 | return; // do nothing |
803 | } |
804 | |
805 | _messMan.register(trcRec, messageType); |
806 | |
807 | } |
808 | |
809 | /** |
810 | * Adds a messagereceiver for tracenotes to the experiment. Whenever a model |
811 | * produces a message of that type, it will also be sent to the given |
812 | * messagereceiver for further processing. Note that the given Receiver must |
813 | * be capable of handling tracenotes. |
814 | * |
815 | * @param trcRec |
816 | * desmoj.report.MessageReceiver : The new messagereceiver for |
817 | * the given type of messages |
818 | */ |
819 | public void addTraceReceiver(MessageReceiver trcRec) { |
820 | |
821 | if (trcRec == null) { |
822 | sendWarning("Can not add receiver to experiment! Command ignored.", |
823 | "Experiment '" + getName() |
824 | + "', method 'void addTraceReceiver(" |
825 | + "MessageReceiver trcRec)'", |
826 | "The parameter 'trc' passed was a null reference.", |
827 | "Make sure to construct a valid MessageReciever before adding it to " |
828 | + "the experiment's messaging system."); |
829 | return; // do nothing |
830 | } |
831 | |
832 | _messMan.register(trcRec, tracenote); |
833 | |
834 | } |
835 | |
836 | /** |
837 | * Returns a boolean indicating whether debug notes are forwarded to the |
838 | * debug ouput or not. Debug ouput can be switched on and off using the |
839 | * methods <code>debugOn(TimeInstant startTime)</code> or |
840 | * <code>debugOff(TimeInstant stopTime)</code> |
841 | * |
842 | * @return boolean |
843 | */ |
844 | public boolean debugIsOn() { |
845 | |
846 | return _messMan.isOn(debugnote); |
847 | |
848 | } |
849 | |
850 | /** |
851 | * Switches the debug output off at the given point of simulation time. |
852 | * |
853 | * @param stopTime |
854 | * TimeInstant : The point in simulation time to switch off debug |
855 | */ |
856 | public void debugOff(TimeInstant stopTime) { |
857 | |
858 | // check initial TimeInstant parameter |
859 | if (stopTime == null) { |
860 | sendWarning( |
861 | "Invalid start time parameter for debug output given! " |
862 | + "StopTime is set to current time.", |
863 | "Experiment '" + getName() |
864 | + "', method 'void debugOn(TimeInstant startTime)'", |
865 | "A null value or a not initialized TimeInstant reference has been passed.", |
866 | "Make sure to have a valid TimeInstant object, otherwise use method " |
867 | + "start() without TimeInstant parameter."); |
868 | stopTime = clientScheduler.presentTime(); |
869 | } |
870 | |
871 | // check if parameter is in future |
872 | if (TimeInstant.isAfter(clientScheduler.presentTime(), stopTime)) { |
873 | sendWarning("Invalid start time parameter for debug output given! " |
874 | + "StopTime is set to current time.", "Experiment '" |
875 | + getName() |
876 | + "', method 'void debugOn(TimeInstant stopTime)'", |
877 | "The stopTime given is in the past.", |
878 | "Make sure to give a TimeInstant parameter larger than the current time."); |
879 | stopTime = clientScheduler.presentTime(); |
880 | } |
881 | |
882 | ExternalEvent debugOff = new ExternalEventDebugOff(_client, true); |
883 | |
884 | debugOff.schedule(stopTime); |
885 | |
886 | } |
887 | |
888 | /** |
889 | * @deprecated Use debugOff(TimeInstant startTime). Switches the debug output off at the given point of simulation time. |
890 | * |
891 | * @param stopTime |
892 | * SimTime : The point in simulation time to switch debug off |
893 | */ |
894 | public void debugOff(SimTime stopTime) { |
895 | this.debugOff(SimTime.toTimeInstant(stopTime)); |
896 | } |
897 | |
898 | /** |
899 | * Switches the debug output on at the given point of simulation time. |
900 | * |
901 | * @param startTime |
902 | * TimeInstant : The point in simulation time to switch on debug |
903 | */ |
904 | public void debugOn(TimeInstant startTime) { |
905 | |
906 | // check initial TimeInstant parameter |
907 | if (startTime == null) { |
908 | sendWarning( |
909 | "Invalid start time parameter for debug output given! " |
910 | + "StartTime is set to current time.", |
911 | "Experiment '" + getName() |
912 | + "', method 'void debugOn(TimeInstant startTime)'", |
913 | "A null value or a not initialized TimeInstant reference has been passed.", |
914 | "Make sure to have a valid TimeInstant object, otherwise use method " |
915 | + "start() without TimeInstant parameter."); |
916 | startTime = clientScheduler.presentTime(); |
917 | } |
918 | |
919 | // check if parameter is in future |
920 | if (TimeInstant.isAfter(clientScheduler.presentTime(), startTime)) { |
921 | sendWarning("Invalid start time parameter for debug output given! " |
922 | + "StartTime is set to current time.", "Experiment '" |
923 | + getName() |
924 | + "', method 'void debugOn(TimeInstant startTime)'", |
925 | "The startTime given is in the past.", |
926 | "Make sure to give a TimeInstant parameter larger than the current time."); |
927 | startTime = clientScheduler.presentTime(); |
928 | } |
929 | |
930 | // if parameter equals current time, set trace on immediately, e.g. |
931 | // to include initial scheduling |
932 | if (TimeInstant.isEqual(clientScheduler.presentTime(), startTime)) { |
933 | this.getMessageManager().switchOn(Experiment.debugnote); |
934 | _client.sendTraceNote("Debug switched on"); |
935 | // Otherwise schedule an appropriate event |
936 | } else { |
937 | ExternalEvent debugOn = new ExternalEventDebugOn(_client, true); |
938 | debugOn.schedule(startTime); |
939 | } |
940 | |
941 | } |
942 | |
943 | /** |
944 | * @deprecated Use debugOn(TimeInstant startTime). Switches the debug output on at the given point of simulation time. |
945 | * |
946 | * @param startTime |
947 | * SimTime : The point in simulation time to switch debug on |
948 | */ |
949 | public void debugOn(SimTime startTime) { |
950 | this.debugOn(SimTime.toTimeInstant(startTime)); |
951 | } |
952 | |
953 | /** |
954 | * Switches the debug output on for the given period of simulation time. If |
955 | * the second parameter (off) is "sooner" then the first parameter (on), |
956 | * they will be swapped automatically. Same parameters will result in no |
957 | * debug output at all! |
958 | * |
959 | * @param startTime |
960 | * TimeInstant : The point in simulation time to switch debug on |
961 | * @param stopTime |
962 | * TimeInstant : The point in simulation time to switch debug off |
963 | */ |
964 | public void debugPeriod(TimeInstant startTime, TimeInstant stopTime) { |
965 | // check initial TimeInstant parameter |
966 | if (startTime == null) { |
967 | sendWarning( |
968 | "Invalid start time parameter for debug output given! Command ignored", |
969 | "Experiment '" + getName() |
970 | + "', Method 'debugPeriod(TimeInstant startTime, " |
971 | + "TimeInstant stopTime)'", |
972 | "A null value or a not initialized TimeInstant reference has been passed.", |
973 | "Make sure to have a valid TimeInstant object."); |
974 | return; |
975 | } |
976 | |
977 | // check initial TimeInstant parameter |
978 | if (stopTime == null) { |
979 | sendWarning( |
980 | "Invalid stop time parameter for debug output given! Command ignored.", |
981 | "Experiment '" + getName() |
982 | + "', Method 'debugPeriod(TimeInstant startTime, " |
983 | + "TimeInstant stopTime)'", |
984 | "A null value or a not initialized TimeInstant reference has been passed.", |
985 | "Make sure to have a valid TimeInstant object."); |
986 | return; |
987 | } |
988 | |
989 | // check for correct order in parameters |
990 | if (TimeInstant.isAfter(startTime, stopTime)) { |
991 | |
992 | // swap parameters |
993 | TimeInstant buffer = stopTime; |
994 | stopTime = startTime; |
995 | startTime = buffer; |
996 | |
997 | } |
998 | |
999 | // check if stop parameter is in future |
1000 | if (TimeInstant.isAfter(clientScheduler.presentTime(), stopTime)) { |
1001 | sendWarning( |
1002 | "Invalid stop time parameter for debug output given! Command ignored.", |
1003 | "Experiment '" + getName() |
1004 | + "', Method 'debugPeriod(TimeInstant startTime, " |
1005 | + "TimeInstant stopTime)'", |
1006 | "The stopTime given is in the past.", |
1007 | "Make sure to give a TimeInstant parameter larger than the current time."); |
1008 | return; |
1009 | } |
1010 | |
1011 | // check if start parameter is in past |
1012 | if (TimeInstant.isAfter(clientScheduler.presentTime(), startTime)) { |
1013 | sendWarning("Invalid start time parameter for debug output given! " |
1014 | + "Debug output has been set to start immediately.", |
1015 | "Experiment '" + getName() |
1016 | + "', Method 'debugPeriod(TimeInstant startTime, " |
1017 | + "TimeInstant stopTime)'", |
1018 | "The startTime given is in the past.", |
1019 | "Make sure to give a TimeInstant parameter larger than the current time."); |
1020 | startTime = clientScheduler.presentTime(); |
1021 | } |
1022 | |
1023 | // set debug to switch on |
1024 | debugOn(startTime); |
1025 | |
1026 | // set debug to switch off |
1027 | debugOff(stopTime); |
1028 | } |
1029 | |
1030 | /** |
1031 | * @deprecated Replaced by debugTime(TimeInstant a, TimeInstant b). Switches |
1032 | * the debug output on for the given period of simulation time. |
1033 | * If the second parameter (off) is "sooner" then the first |
1034 | * parameter (on), they will be swapped automatically. Same |
1035 | * parameters will result in no debug output at all! |
1036 | * |
1037 | * @param startTime |
1038 | * SimTime : The point in simulation time to switch debug on |
1039 | * @param stopTime |
1040 | * SimTime : The point in simulation time to switch debug off |
1041 | */ |
1042 | @Deprecated |
1043 | public void debugPeriod(SimTime startTime, SimTime stopTime) { |
1044 | debugPeriod(SimTime.toTimeInstant(startTime), SimTime |
1045 | .toTimeInstant(stopTime)); |
1046 | } |
1047 | |
1048 | /** |
1049 | * De-registers a file at the experiment. Registered files will be flushed |
1050 | * and closed after the experiment has finished. If the file is manually |
1051 | * closed by the user and has been registered at the Experiment, deRegister |
1052 | * it |
1053 | * |
1054 | * @param file |
1055 | * desmoj.report.FileOutput : The file to be closed with the end |
1056 | * of an Experiment |
1057 | */ |
1058 | public void deRegister(FileOutput file) { |
1059 | |
1060 | if (file == null) { |
1061 | sendWarning("Can not de-register FileOutput! Command ignored.", |
1062 | "Experiment '" + getName() |
1063 | + "' method 'void deRegister(FileOutput file).'", |
1064 | "The parameter given was a null reference.", |
1065 | "Make sure to only connect valid FileOutputs at the Experiment."); |
1066 | return; |
1067 | } |
1068 | |
1069 | _registryFileOutput.remove(file); |
1070 | // remove whether it was inside or not |
1071 | |
1072 | } |
1073 | |
1074 | /** |
1075 | * Stopps all running simprocesses that might still be scheduled and closes |
1076 | * the output files. |
1077 | */ |
1078 | public void finish() { |
1079 | |
1080 | // check if experiment has not been aborted before |
1081 | if (_status >= ABORTED) { |
1082 | return; |
1083 | } |
1084 | |
1085 | if (_traceOutput != null) { |
1086 | for (OutputType trc : _traceOutput) |
1087 | { |
1088 | if (trc instanceof OutputTypeEndToExport) { |
1089 | ((OutputTypeEndToExport) trc).export(_pathName, getName()); |
1090 | } |
1091 | } |
1092 | } |
1093 | if (_debugOutput != null) { |
1094 | for (OutputType dbg : _debugOutput) { |
1095 | if (dbg instanceof OutputTypeEndToExport) { |
1096 | ((OutputTypeEndToExport) dbg).export(_pathName, getName()); |
1097 | } |
1098 | } |
1099 | } |
1100 | if (_errorOutput != null) { |
1101 | for (OutputType err : _errorOutput) { |
1102 | if (err instanceof OutputTypeEndToExport) { |
1103 | ((OutputTypeEndToExport) err).export(_pathName, getName()); |
1104 | } |
1105 | } |
1106 | } |
1107 | if (_reportOutput != null){ |
1108 | for (OutputType rpt : _reportOutput) { |
1109 | if (rpt instanceof OutputTypeEndToExport){ |
1110 | ((OutputTypeEndToExport) rpt).export(_pathName, getName()); |
1111 | } |
1112 | } |
1113 | } |
1114 | |
1115 | // set status to let all simthreads be killed |
1116 | _status = ABORTED; |
1117 | |
1118 | // close all files still open |
1119 | for (OutputType o : _registryOutputType) |
1120 | o.close(); |
1121 | for (FileOutput f : _registryFileOutput) |
1122 | f.close(); |
1123 | |
1124 | // kill all SimThreads still active |
1125 | Thread[] survivors = new Thread[_expThreads.activeCount()]; |
1126 | _expThreads.enumerate(survivors); |
1127 | |
1128 | for (int i = 0; i < survivors.length; i++) { |
1129 | |
1130 | // print existing threads for controlling purposes only |
1131 | // System.out.println(survivors[i]); |
1132 | |
1133 | // if we get the enumeration of survivors, some of them |
1134 | // might not have made it until here and die in between |
1135 | // so an occasional NullPointerException is perfectly |
1136 | // alright and no reason to worry -> we just dump it. |
1137 | if (survivors[i] instanceof SimThread) { |
1138 | try { |
1139 | ((SimThread) survivors[i]).kill(); |
1140 | } catch (NullPointerException e) { |
1141 | ; // forget it anyway... |
1142 | } |
1143 | } |
1144 | } |
1145 | |
1146 | } |
1147 | |
1148 | /** |
1149 | * Returns the distributionmanager for this experiment. Distributions need |
1150 | * access to the distributionmanager for handling antithetic modes, |
1151 | * resetting and their initial seeds. |
1152 | * |
1153 | * @return desmoj.dist.DistributionManager : The distributionmanager for |
1154 | * this experiment |
1155 | */ |
1156 | public DistributionManager getDistributionManager() { |
1157 | |
1158 | return _distMan; |
1159 | |
1160 | } |
1161 | |
1162 | /** |
1163 | * Returns the epsilon value representing the granularity |
1164 | * of simulation time for this experiment. So far, Hour, Minute, |
1165 | * Second and Millisecond are supported. |
1166 | * Default (unless set explicitly) is TimeUnit.MICROSECONDS. |
1167 | * |
1168 | * @return TimeUnit : The Granularity of the simulation time |
1169 | */ |
1170 | public TimeUnit getEpsilonUnit() { |
1171 | |
1172 | return TimeOperations.getEpsilon(); |
1173 | } |
1174 | |
1175 | /** |
1176 | * @deprecated Use getEpsilonUnit(). |
1177 | * Returns a SimTime representation of the granularity of simulation time |
1178 | * for this experiment. So far, Hour, Minute, |
1179 | * Second and Millisecond are supported. |
1180 | * |
1181 | * @return SimTime : The Granularity of the simulation time |
1182 | */ |
1183 | public SimTime getEpsilon() { |
1184 | |
1185 | return SimTime.toSimTime(new TimeSpan (1L, TimeOperations.getEpsilon())); |
1186 | } |
1187 | |
1188 | /** |
1189 | * Returns the current execution Speed Rate. |
1190 | * |
1191 | * @return double : The current execution speed rate. |
1192 | */ |
1193 | public double getExecutionSpeedRate() { |
1194 | return this.clientScheduler.getExecutionSpeedRate(); |
1195 | } |
1196 | |
1197 | /** |
1198 | * Returns the messagemanager for this experiment. Messages need access to |
1199 | * the MessageManager for distributing the messages to one or more specified |
1200 | * output streams. |
1201 | * |
1202 | * @return desmoj.dist.MessageManager : The messagemanager for this |
1203 | * experiment |
1204 | */ |
1205 | public MessageDistributor getMessageManager() { |
1206 | |
1207 | return _messMan; |
1208 | |
1209 | } |
1210 | |
1211 | /** |
1212 | * Returns the model that is connected to this experiment or |
1213 | * <code>null</code> if no model is connected so far. |
1214 | * |
1215 | * @return Model : The model that this experiment is connected to or |
1216 | * <code>null</code> if no connection is established. |
1217 | */ |
1218 | public Model getModel() { |
1219 | |
1220 | return _client; |
1221 | |
1222 | } |
1223 | |
1224 | /** |
1225 | * Returns the name of the path the experiment's report-, trace-, debug- and |
1226 | * error-files are written to. |
1227 | * |
1228 | * @return String the experiment's output path |
1229 | */ |
1230 | public String getOutputPath() { |
1231 | return new File(_pathName).getAbsolutePath(); |
1232 | } |
1233 | |
1234 | public List<List<String>> getOutputAppendixes() { |
1235 | |
1236 | List<List<String>> appendixes = new ArrayList<List<String>>(); |
1237 | |
1238 | ArrayList<String> debugAppendixes = new ArrayList<String>(); |
1239 | for (OutputType o : this._debugOutput) { |
1240 | debugAppendixes.add(o.getAppendix()); |
1241 | } |
1242 | appendixes.add(debugAppendixes); |
1243 | |
1244 | ArrayList<String> traceAppendixes = new ArrayList<String>(); |
1245 | for (OutputType o : this._debugOutput) { |
1246 | traceAppendixes.add(o.getAppendix()); |
1247 | } |
1248 | appendixes.add(traceAppendixes); |
1249 | |
1250 | ArrayList<String> errorAppendixes = new ArrayList<String>(); |
1251 | for (OutputType o : this._debugOutput) { |
1252 | errorAppendixes.add(o.getAppendix()); |
1253 | } |
1254 | appendixes.add(errorAppendixes); |
1255 | |
1256 | ArrayList<String> reportAppendixes = new ArrayList<String>(); |
1257 | for (OutputType o : this._debugOutput) { |
1258 | reportAppendixes.add(o.getAppendix()); |
1259 | } |
1260 | appendixes.add(reportAppendixes); |
1261 | |
1262 | return appendixes; |
1263 | } |
1264 | |
1265 | public long getRealTimeStartTime() { |
1266 | return _realTimeStartTime; |
1267 | } |
1268 | |
1269 | /** |
1270 | * Returns the reference unit for this experiment. This is the time unit |
1271 | * mapped to a time step of 1.0 in simulation time. So far, Hour, Minute, |
1272 | * Second and Millisecond are supported. |
1273 | * Default (unless set explicitly) is TimeUnit.SECONDS. |
1274 | * |
1275 | * @return TimeUnit : The reference unit. |
1276 | */ |
1277 | public TimeUnit getReferenceUnit() { |
1278 | return TimeOperations.getReferenceUnit(); |
1279 | } |
1280 | |
1281 | /** |
1282 | * Returns the resource database for this experiment. The <code>Res</code> |
1283 | * objects need access to the resource database to note their resource |
1284 | * allocations and requests and for deadlock detection. |
1285 | * |
1286 | * @return desmoj.ResourceDB : the resource database storing all resource |
1287 | * allocations and requests. |
1288 | * @author Soenke Claassen |
1289 | */ |
1290 | public ResourceDB getResourceDB() { |
1291 | |
1292 | return _resDB; |
1293 | } |
1294 | |
1295 | /** |
1296 | * Returns the scheduler for this experiment. ModelComponents need access to |
1297 | * the scheduler for identifying the current active entity or process and to |
1298 | * schedule themselves or other schedulables to activate at a given time in |
1299 | * the future. |
1300 | * |
1301 | * @return Scheduler : The scheduler for this experiment |
1302 | */ |
1303 | public Scheduler getScheduler() { |
1304 | |
1305 | return clientScheduler; |
1306 | |
1307 | } |
1308 | |
1309 | /** |
1310 | * Returns the simclock for this experiment. ModelComponents need access to |
1311 | * the simclock for retrieveing the current simulation time. |
1312 | * |
1313 | * @return SimCLock : The simclock for this experiment |
1314 | */ |
1315 | public SimClock getSimClock() { |
1316 | |
1317 | return clientScheduler.getSimClock(); |
1318 | |
1319 | } |
1320 | |
1321 | /** |
1322 | * Returns the TimeInstant when the experiment is expected to stop running. |
1323 | * |
1324 | * @return desmoj.TimeInstant : The time, the experiment is expected to stop |
1325 | * running. |
1326 | */ |
1327 | public TimeInstant getStopTime() { |
1328 | |
1329 | return _stopTime; |
1330 | } |
1331 | |
1332 | /** |
1333 | * Returns the Conditions which can cause an experiment to stop. |
1334 | * May be empty if there are no such Conditions. |
1335 | * |
1336 | * @return Condition |
1337 | * @author Tim Janz |
1338 | */ |
1339 | public List<ModelCondition> getStopConditions() { |
1340 | |
1341 | return new java.util.ArrayList<ModelCondition>(this._stopConditions); |
1342 | } |
1343 | |
1344 | /** |
1345 | * Removes all conditions set to stop the experiment. |
1346 | */ |
1347 | public void removeStopConditions() { |
1348 | |
1349 | this._stopConditions.clear(); |
1350 | } |
1351 | |
1352 | /** |
1353 | * Returns the threadgroup associated to this experiment. All Threads are |
1354 | * associated to this threadgroup to get control of their number and state |
1355 | * and to have a means to differentiate them from possible other |
1356 | * experiments' threads. |
1357 | * |
1358 | * @return java.lang.ThreadGroup |
1359 | */ |
1360 | ThreadGroup getThreadGroup() { |
1361 | |
1362 | return _expThreads; |
1363 | |
1364 | } |
1365 | |
1366 | /** |
1367 | * @deprecated Depends on TimeFormatter in use. Returns the experiment's number |
1368 | * of floating point digits of simulation time that are displayed in the various output files, |
1369 | * as read from the SingleUnitTimeFormatter, if in use. Otherwise, 0 will be returned. |
1370 | * |
1371 | * @return int : The number of floating point digits of simulation time to |
1372 | * be displayed in output files |
1373 | */ |
1374 | public int getTimeFloats() { |
1375 | |
1376 | if (TimeOperations.getTimeFormatter() instanceof SingleUnitTimeFormatter) { |
1377 | return (int) ((SingleUnitTimeFormatter)TimeOperations.getTimeFormatter())._floats; |
1378 | } else |
1379 | return 0; |
1380 | } |
1381 | |
1382 | /** |
1383 | * Displays the current state of the simulation run. If an experient is |
1384 | * aborted, it can not be proceeded. All SimThreads still active are |
1385 | * stopped, the main routine can finish. |
1386 | * |
1387 | * @return boolean : Is <code>true</code> if the simulation is aborted, |
1388 | * <code>false</code> if it has not started yet or is still running |
1389 | */ |
1390 | public boolean isAborted() { |
1391 | |
1392 | return (_status >= ABORTED); |
1393 | |
1394 | } |
1395 | |
1396 | /** |
1397 | * Shows if this experiment has already been connected to a model. |
1398 | * |
1399 | * @return boolean : Is <code>true</code>, if experiment is connected to a |
1400 | * model, <code>false</code> otherwise |
1401 | */ |
1402 | public boolean isConnected() { |
1403 | |
1404 | return (_status >= CONNECTED); // model connected |
1405 | |
1406 | } |
1407 | |
1408 | /** |
1409 | * Returns if the event-list processes concurrent Events in random order or |
1410 | * not. Default is not. |
1411 | * |
1412 | * @return boolean: <code>true</code> if concurrent Events are randomized, |
1413 | * <code>false</code> otherwise |
1414 | * @author Ruth Meyer |
1415 | */ |
1416 | public boolean isRandomizingConcurrentEvents() { |
1417 | return clientScheduler.isRandomizingConcurrentEvents(); |
1418 | } |
1419 | |
1420 | /** |
1421 | * Displays the current state of the simulation run. |
1422 | * |
1423 | * @return boolean : Is <code>true</code> if the simulation is running, |
1424 | * <code>false</code> if it has not started yet or has already |
1425 | * finished |
1426 | */ |
1427 | public boolean isRunning() { |
1428 | |
1429 | return (_status == RUNNING); |
1430 | |
1431 | } |
1432 | |
1433 | /** |
1434 | * Returns if a progress bar should be displayed for this experiment or not. |
1435 | * |
1436 | * @return boolean :<code>true</code> if a progress bar should be displayed |
1437 | * for this experiment, <code>false</code> otherwise. |
1438 | */ |
1439 | public boolean isShowProgressBar() { |
1440 | |
1441 | return _showProgressBar; |
1442 | } |
1443 | |
1444 | /** |
1445 | * Displays the current state of the simulation run. If an experient is |
1446 | * stopped, it can be proceeded by calling proceed(). |
1447 | * |
1448 | * @return boolean : Is <code>true</code>, if experiment is stopped, |
1449 | * <code>false</code> otherwise |
1450 | */ |
1451 | public boolean isStopped() { |
1452 | |
1453 | return (_status == STOPPED); // model stopped |
1454 | |
1455 | } |
1456 | |
1457 | /** |
1458 | * Proceeds with a stopped experiment. An experiment can be stopped, if |
1459 | * either its status is changed from <code>RUNNING</code> to some other |
1460 | * state, the scheduler runs out of scheduled events or if the |
1461 | * <code>check()</code> method of the given stop <code>Condition</code> |
1462 | * returns <code>true</code> after an event has been processed. |
1463 | */ |
1464 | public void proceed() { |
1465 | |
1466 | if (_status < STARTED) { |
1467 | sendWarning( |
1468 | "Can not proceed with Experiment! Command ignored.", |
1469 | "Experiment: " + getName() + " Method: void proceed().", |
1470 | "The Experiment has not been started yet.", |
1471 | "Only Experiments that have been stopped after method 'start()' has " |
1472 | + "been called can use method 'proceed()' to continue."); |
1473 | return; |
1474 | } |
1475 | |
1476 | if (_status > STOPPED) { |
1477 | sendWarning("Can not proceed with Experiment! Command ignored.", |
1478 | "Experiment " + getName() + " Method: void proceed().", |
1479 | "The Experiment has already been aborted.", |
1480 | "Use method 'proceed()' only on stopped experiments."); |
1481 | return; |
1482 | } |
1483 | if (_status == STARTED) { |
1484 | // print status message to calm users waiting long, long, long |
1485 | // hours... |
1486 | if (!_silent) System.out.println("***** DESMO-J version " + getDesmoJVersion() |
1487 | + " ***** \n" + getName() + " starts at simulation time " |
1488 | + getScheduler().presentTime() + "\n ...please wait..."); |
1489 | } |
1490 | else{ |
1491 | if (!_silent) System.out.println(getName() + " resumes at simulation time " |
1492 | + getScheduler().presentTime() + "\n ...please wait..."); |
1493 | } |
1494 | // display a progress bar if stop time is known and showProgressBar is |
1495 | // true |
1496 | if (_stopTime != null && _showProgressBar) { |
1497 | JFrame frame = new ExpProgressBar(this); |
1498 | |
1499 | frame.addWindowListener(new WindowAdapter() { |
1500 | public void windowClosing(WindowEvent e) { |
1501 | System.exit(0); |
1502 | } |
1503 | }); |
1504 | |
1505 | frame.pack(); |
1506 | // frame.setSize(380,90); |
1507 | frame.setVisible(true); |
1508 | } |
1509 | |
1510 | _status = RUNNING; // now checked to run |
1511 | boolean gotEvent = false; // buffer to check if scheduler works |
1512 | |
1513 | try { |
1514 | |
1515 | while (_status == RUNNING) { |
1516 | // infinite loop until condition/time expired |
1517 | gotEvent = clientScheduler.processNextEventNote(); |
1518 | if (gotEvent == false) { |
1519 | _status = STOPPED; |
1520 | } |
1521 | |
1522 | // check potential stop conditions |
1523 | if (!_stopConditions.isEmpty()) { |
1524 | for (ModelCondition c : _stopConditions) { |
1525 | if (c.check()) { |
1526 | _status = STOPPED; |
1527 | break; |
1528 | } |
1529 | } |
1530 | } |
1531 | |
1532 | // Sleep a while (modified by N. Knaak) |
1533 | if (_status == RUNNING && _delayInMillis != 0) |
1534 | Thread.sleep(_delayInMillis); |
1535 | } |
1536 | } catch (DESMOJException e) { |
1537 | System.err.println("desaster recovery"); |
1538 | // this is the desaster recovery routine to stop simulation and save |
1539 | // the report to disc before exiting the faulty experiment |
1540 | _messMan.receive(e.getErrorMessage()); |
1541 | report(); |
1542 | finish(); |
1543 | _status = ABORTED; |
1544 | e.printStackTrace(); |
1545 | } catch (java.lang.InterruptedException e) { |
1546 | System.err.println("desaster recovery"); |
1547 | // this is the disaster recovery routine to stop simulation and save |
1548 | // the report to disc before exiting the faulty experiment |
1549 | // messMan.receive(e.getMessage()); |
1550 | report(); |
1551 | finish(); |
1552 | _status = ABORTED; |
1553 | } |
1554 | |
1555 | // give warning if reason for stopping was empty EventList |
1556 | if (gotEvent == false) { |
1557 | sendWarning("No more events scheduled! Experiment is stopped.", |
1558 | "Experiment '" + getName() + "' method void proceed().", |
1559 | "The scheduler has run out of events to handle.", |
1560 | "Make sure to always have events to be scheduled i.e. by letting an " |
1561 | + "Entity create and schedule its successor."); |
1562 | } |
1563 | |
1564 | // print status message to user... |
1565 | if (!_silent) System.out.println(getName() + " stopped at simulation time " |
1566 | + getScheduler().presentTime()); |
1567 | |
1568 | } |
1569 | |
1570 | /** |
1571 | * Sets the delay between each step of the scheduler. |
1572 | * |
1573 | * @param delay |
1574 | * : Delay time in milliseconds as a long value |
1575 | * @author Nicolas Knaak |
1576 | */ |
1577 | public void setDelayInMillis(long delay) { |
1578 | _delayInMillis = delay; |
1579 | } |
1580 | |
1581 | /** |
1582 | * Returns the delay between each step of the scheduler |
1583 | * |
1584 | * @return A long value representing the delay time in milliseconds |
1585 | * @author Nicolas Knaak |
1586 | * |
1587 | */ |
1588 | public long getDelayInMillis() { |
1589 | return _delayInMillis; |
1590 | } |
1591 | |
1592 | |
1593 | /** |
1594 | * Registers a file output (Report, Trace, Error, Debug) in specific formats |
1595 | * (e.g. HTML, ASCII, XML) at the experiment. Registered files will be |
1596 | * flushed and closed after the experiment has finished. This is handy for |
1597 | * modellers producing their own output who want their files to be closed at |
1598 | * the end of the experiment. |
1599 | * |
1600 | * @param file |
1601 | * desmoj.report.FileOutput : The file to be closed with the end |
1602 | * of an experiment |
1603 | */ |
1604 | public void register(OutputType file) { |
1605 | |
1606 | if (file == null) { |
1607 | sendWarning("Can not register OutputType! Command ignored.", |
1608 | "Experiment '" + getName() |
1609 | + "' method void register(OutputType file).", |
1610 | "The parameter given was a null reference.", |
1611 | "Make sure to only connect valid OutputType at the Experiment."); |
1612 | return; |
1613 | } |
1614 | |
1615 | if (_registryOutputType.contains(file)) |
1616 | return; // file already registered |
1617 | |
1618 | _registryOutputType.add(file); |
1619 | |
1620 | } |
1621 | |
1622 | /** |
1623 | * Registers a custom file output at the experiment, e.g. TimeSeries |
1624 | * plotting data to a file. Registered files will be flushed and closed |
1625 | * after the experiment has finished. This is handy for modellers producing |
1626 | * their own output who want their files to be closed at the end of the |
1627 | * experiment. |
1628 | * |
1629 | * @param file |
1630 | * desmoj.report.FileOutput : The file to be closed with the end |
1631 | * of an experiment |
1632 | */ |
1633 | public void registerFileOutput(FileOutput file) { |
1634 | |
1635 | if (file == null) { |
1636 | sendWarning("Can not register FileOutput! Command ignored.", |
1637 | "Experiment '" + getName() |
1638 | + "' method void register(OutputType file).", |
1639 | "The parameter given was a null reference.", |
1640 | "Make sure to only connect valid FileOutput at the Experiment."); |
1641 | return; |
1642 | } |
1643 | |
1644 | if (_registryFileOutput.contains(file)) |
1645 | return; // file already registered |
1646 | |
1647 | _registryFileOutput.add(file); |
1648 | |
1649 | } |
1650 | |
1651 | /** |
1652 | * Connects a model to this experiment. The given model must not be submodel |
1653 | * of other models and not already be connected to some other experiment. |
1654 | * Otherwise an errormessage will be given and the experiment will be |
1655 | * stopped. |
1656 | */ |
1657 | void registerModel(Model mainModel) { |
1658 | |
1659 | if (mainModel == null) { |
1660 | sendWarning( |
1661 | "Can not register model at experiment! Command ignored.", |
1662 | "Experiment '" + getName() |
1663 | + "', Method 'void registerModel(Model mainModel)'", |
1664 | "The parameter passed was a null reference.", |
1665 | "Make sure to connect a valid main model to this experiment."); |
1666 | return; // no connection possible. |
1667 | } |
1668 | |
1669 | if (mainModel.getModel() != null) { |
1670 | sendWarning( |
1671 | "Can not register model at experiment! Command ignored.", |
1672 | "Experiment '" + getName() |
1673 | + "', Method 'void registerModel(Model mainModel)'", |
1674 | "The model references another model as its owner, thus can not be the " |
1675 | + "main model.", |
1676 | "Make sure to connect a valid main model to this experiment."); |
1677 | return; // no connection possible. |
1678 | } |
1679 | |
1680 | if (isConnected()) { |
1681 | sendWarning( |
1682 | "Can not register model at experiment! Command ignored.", |
1683 | "Experiment '" + getName() |
1684 | + "', Method 'void registerModel(Model mainModel)'", |
1685 | "This experiment is already connected to model : " |
1686 | + _client.getName(), |
1687 | "An experiment may only be connected to one main model at a time."); |
1688 | return; // no connection possible. |
1689 | } |
1690 | |
1691 | _status = CONNECTED; |
1692 | _client = mainModel; |
1693 | _client.setMain(); |
1694 | |
1695 | } |
1696 | |
1697 | /** |
1698 | * Removes a messagereceiver for debugnotes from the experiment's |
1699 | * messagedistributor. Whenever a model produces a message of that type, it |
1700 | * will not be sent to the given messagereceiver anymore. Note that if the |
1701 | * messagereceiver is also registered for other types of messages, these |
1702 | * will not be affected. Use method |
1703 | * <code>removeReceiverAll(MessageReceiver msgRec)</code> to remove a |
1704 | * messagereceiver from all types of messages. |
1705 | * |
1706 | * @param msgRec |
1707 | * desmoj.report.MessageReceiver : The new messagereceiver to be |
1708 | * removed from the messagedistributor's list for the given |
1709 | * messagetype |
1710 | */ |
1711 | public void removeDebugReceiver(MessageReceiver msgRec) { |
1712 | |
1713 | if (msgRec == null) { |
1714 | sendWarning( |
1715 | "Can not remove receiver to experiment! Command ignored.", |
1716 | "Experiment '" + getName() |
1717 | + "', Method 'void removeDebugReceiver" |
1718 | + "(MessageReceiver msgRec)'", |
1719 | "The parameter 'msgRec' passed was a null reference.", |
1720 | "Make sure to give a valid MessageReciever reference before removing it " |
1721 | + "from the experiment's messaging system."); |
1722 | return; // do nothing |
1723 | } |
1724 | |
1725 | _messMan.deRegister(msgRec, debugnote); |
1726 | |
1727 | } |
1728 | |
1729 | /** |
1730 | * Removes a messagereceiver for errormessages from the experiment's |
1731 | * messagedistributor. Whenever a model produces a message of that type, it |
1732 | * will not be sent to the given messagereceiver anymore. Note that if the |
1733 | * messagereceiver is also registered for other types of messages, these |
1734 | * will not be affected. Use method |
1735 | * <code>removeReceiverAll(MessageReceiver msgRec)</code> to remove a |
1736 | * messagereceiver from all types of messages. |
1737 | * |
1738 | * @param msgRec |
1739 | * desmoj.report.MessageReceiver : The new messagereceiver to be |
1740 | * removed from the vessagedistributor's list for the given |
1741 | * messagetype |
1742 | */ |
1743 | public void removeErrorReceiver(MessageReceiver msgRec) { |
1744 | |
1745 | if (msgRec == null) { |
1746 | sendWarning( |
1747 | "Can not remove receiver to experiment! Command ignored.", |
1748 | "Experiment '" + getName() |
1749 | + "', Method 'void removeErrorReceiver" |
1750 | + "(MessageReceiver msgRec)'", |
1751 | "The parameter 'msgRec' passed was a null reference.", |
1752 | "Make sure to give a valid MessageReciever reference before removing it " |
1753 | + "from the experiment's messaging system."); |
1754 | return; // do nothing |
1755 | } |
1756 | |
1757 | _messMan.deRegister(msgRec, errormessage); |
1758 | |
1759 | } |
1760 | |
1761 | /** |
1762 | * Removes a messagereceiver from the experiment's messagedistributor. The |
1763 | * given messagereceiver will not receive messages of any type any more Use |
1764 | * method <code>removeReceiver(MessageReceiver msgRec, Class |
1765 | * messageType)</code> to remove the messagereceiver from one type of |
1766 | * messages only. |
1767 | * |
1768 | * @param msgRec |
1769 | * desmoj.report.MessageReceiver : The new messagereceiver to be |
1770 | * removed from the messagedistributor's list for the given |
1771 | * messagetype |
1772 | */ |
1773 | public void removeReceiver(MessageReceiver msgRec) { |
1774 | |
1775 | if (msgRec == null) { |
1776 | sendWarning( |
1777 | "Can not remove receiver to experiment! Command ignored.", |
1778 | "Experiment '" + getName() |
1779 | + "', Method 'void removeReceiver(MessageReceiver " |
1780 | + "msgRec)'", |
1781 | "The parameter 'msgRec' passed was a null reference.", |
1782 | "Make sure to give a valid MessageReciever reference before removing it " |
1783 | + "from the experiment's messaging system."); |
1784 | return; // do nothing |
1785 | } |
1786 | |
1787 | _messMan.deRegister(msgRec); |
1788 | |
1789 | } |
1790 | |
1791 | /** |
1792 | * Removes a messagereceiver for the given subtype of message from the |
1793 | * Experiment's messagedistributor. Whenever a model produces a message of |
1794 | * that type, it will not be sent to the given messagereceiver anymore. Note |
1795 | * that if the messagereceiver is also registered for other types of |
1796 | * messages, these will not be affected. Use method |
1797 | * <code>removeReceiverAll(MessageReceiver msgRec)</code> to remove a |
1798 | * messagereceiver from all types of messages. |
1799 | * |
1800 | * @param msgRec |
1801 | * desmoj.report.MessageReceiver : The new messagereceiver to be |
1802 | * removed from the messagedistributor's list for the given |
1803 | * messagetype |
1804 | * @param messageType |
1805 | * Class : The type of message not to be sent to the given |
1806 | * messagereceiver |
1807 | */ |
1808 | public void removeReceiver(MessageReceiver msgRec, Class<?> messageType) { |
1809 | |
1810 | if (msgRec == null) { |
1811 | sendWarning( |
1812 | "Can not remove receiver to experiment! Command ignored.", |
1813 | "Experiment '" + getName() |
1814 | + "', Method 'void removeReceiver(MessageReceiver " |
1815 | + "msgRec, Class messageType)'", |
1816 | "The parameter 'msgRec' passed was a null reference.", |
1817 | "Make sure to give a valid MessageReciever reference before removing it " |
1818 | + "from the experiment's messaging system."); |
1819 | return; // do nothing |
1820 | } |
1821 | |
1822 | if (messageType == null) { |
1823 | sendWarning( |
1824 | "Can not remove receiver to experiment! Command ignored.", |
1825 | "Experiment '" + getName() |
1826 | + "', Method 'void removeReceiver(MessageReceiver " |
1827 | + "msgRec, Class messageType)'", |
1828 | "The parameter 'msgRec' passed was a null reference.", |
1829 | "Make sure to give a valid MessageReciever reference before removing it " |
1830 | + "from the experiment's messaging system."); |
1831 | return; // do nothing |
1832 | } |
1833 | |
1834 | _messMan.deRegister(msgRec, messageType); |
1835 | |
1836 | } |
1837 | |
1838 | /** |
1839 | * Removes a messagereceiver for tracenotes from the experiment's |
1840 | * messagedistributor. Whenever a model produces a message of that type, it |
1841 | * will not be sent to the given messagereceiver anymore. Note that if the |
1842 | * messagereceiver is also registered for other types of messages, these |
1843 | * will not be affected. Use method |
1844 | * <code>removeReceiverAll(MessageReceiver msgRec)</code> to remove a |
1845 | * messagereceiver from all types of messages. |
1846 | * |
1847 | * @param msgRec |
1848 | * desmoj.report.MessageReceiver : The new messagereceiver to be |
1849 | * removed from the messagedistributor's list for the given |
1850 | * messagetype |
1851 | */ |
1852 | public void removeTraceReceiver(MessageReceiver msgRec) { |
1853 | |
1854 | if (msgRec == null) { |
1855 | sendWarning( |
1856 | "Can not remove receiver to experiment! Command ignored.", |
1857 | "Experiment '" + getName() |
1858 | + "', Method 'void removeTraceReceiver" |
1859 | + "(MessageReceiver msgRec)'", |
1860 | "The parameter 'msgRec' passed was a null reference.", |
1861 | "Make sure to give a valid MessageReciever reference before removing it " |
1862 | + "from the experiment's messaging system."); |
1863 | return; // do nothing |
1864 | } |
1865 | |
1866 | _messMan.deRegister(msgRec, tracenote); |
1867 | |
1868 | } |
1869 | |
1870 | /** |
1871 | * Overrides inherited <code>NamedObjectImp.rename(String newName)</code> |
1872 | * method to prevent the user from changing the experiment's name during an |
1873 | * experiment. Renaming is not allowed with experiments, since it would not |
1874 | * allow the user to identify the reports produced by an experiment. The |
1875 | * method simply returns without changing the experiment's name, ignoring |
1876 | * the given parameter. |
1877 | * |
1878 | * @param newName |
1879 | * java.lang.String : The parameter given is not taken as the new |
1880 | * name, method simply returns |
1881 | */ |
1882 | public void rename(String newName) { |
1883 | |
1884 | // do nothing since renaming experiments is not allowed |
1885 | // would do too much confusion |
1886 | |
1887 | } |
1888 | |
1889 | /** |
1890 | * Writes a report about the model connected top this experiment, its |
1891 | * reportable components and all related submodels into the report output. |
1892 | * Note that a report can only be produced, if a valid main model is already |
1893 | * connected to the experiment. |
1894 | */ |
1895 | public void report() { |
1896 | |
1897 | // just pass on the call with main model as parameter |
1898 | report(_client); |
1899 | |
1900 | } |
1901 | |
1902 | /** |
1903 | * Writes a report about the given model which has to be connected to this |
1904 | * experiment as main model or as a submodel. Note that this will report |
1905 | * about a branch of the tree of submodels constructed. A report will only |
1906 | * be produced, if the model given is connected to this experiment. All |
1907 | * reportable components of this model and all related submodels will be |
1908 | * sent to the report output configured at the experiment's |
1909 | * messagedistributor. Note that a report can only be produced, if a valid |
1910 | * main model is already connected to the experiment. |
1911 | */ |
1912 | public void report(Model m) { |
1913 | |
1914 | List<Reporter> reporters; |
1915 | // buffer for the reportmanager returned by client |
1916 | |
1917 | if (_status < CONNECTED) { |
1918 | sendWarning( |
1919 | "Can not produce report! Command ignored.", |
1920 | "Experiment: " + getName() |
1921 | + " Method: void report(Model m).", |
1922 | "The Experiment has not been connected to a model to report about yet.", |
1923 | "Connect a model to the experiment first using the model's method " |
1924 | + "connectToExperiment(Experiment exp)."); |
1925 | return; // no client there to be reported |
1926 | } |
1927 | |
1928 | if (_status >= ABORTED) { |
1929 | // do nothing since experiment has already been aborted and all |
1930 | // output channels are already shut down |
1931 | return; // Experiment aborted |
1932 | } |
1933 | |
1934 | if (m == null) { |
1935 | sendWarning("Can not produce report! Command ignored.", |
1936 | "Experiment: " + getName() |
1937 | + " Method: void report(Model m).", |
1938 | "The model parameter given is a null reference.", |
1939 | "Always make sure to use valid references."); |
1940 | return; // no model there to be reported |
1941 | } |
1942 | |
1943 | if (m.getExperiment() != this) { |
1944 | sendWarning( |
1945 | "Can not produce report! Command ignored.", |
1946 | "Experiment: " + getName() |
1947 | + " Method: void report(Model m).", |
1948 | "The model parameter given is connected to a different experiment.", |
1949 | "Only experiments connected to theat model can produce reports " |
1950 | + "about that model."); |
1951 | return; // model connected to other experiment |
1952 | } |
1953 | |
1954 | // get the client's reportmanager containing all reporters in sorted |
1955 | // order |
1956 | reporters = m.report(); |
1957 | |
1958 | // get all out according to sorted order and send them to the report |
1959 | // output |
1960 | // registered at the experiment's messagemanager |
1961 | for (Reporter r : reporters) { |
1962 | |
1963 | _messMan.receive(r); |
1964 | |
1965 | } |
1966 | } |
1967 | |
1968 | /** |
1969 | * Creates and sends a debugnote to the messagedistributor. Be sure to have |
1970 | * a correct location, since the object and method that the error becomes |
1971 | * apparent is not necessary the location it was produced in. The |
1972 | * information about the simulation time is extracted from the Experiment |
1973 | * and must not be given as a parameter. |
1974 | * |
1975 | * @param description |
1976 | * java.lang.String : The description of the error that occured |
1977 | */ |
1978 | void sendDebugNote(String component, String description) { |
1979 | |
1980 | // comnpose the DebugNote and send it in one command |
1981 | sendMessage(new DebugNote(clientScheduler.getCurrentModel(), |
1982 | clientScheduler.getSimClock().getTime(), component, description)); |
1983 | |
1984 | } |
1985 | |
1986 | /** |
1987 | * Sends a message to the messagedistributor. Note that there are other |
1988 | * shorthands for sending the standard DESMO-J messages. |
1989 | * |
1990 | * @param m |
1991 | * Message : The Message to be transmitted |
1992 | * @see ModelComponent#sendTraceNote |
1993 | * @see ModelComponent#sendDebugNote |
1994 | * @see ModelComponent#sendWarning |
1995 | */ |
1996 | void sendMessage(Message m) { |
1997 | |
1998 | if (m == null) { |
1999 | sendWarning("Can't send Message!", "Experiment :" + getName() |
2000 | + " Method: SendMessage(Message m)", |
2001 | "The Message given as parameter is a null reference.", |
2002 | "Be sure to have a valid Message reference."); |
2003 | return; // no proper parameter |
2004 | } |
2005 | |
2006 | _messMan.receive(m); |
2007 | |
2008 | } |
2009 | |
2010 | /** |
2011 | * Creates and sends an error message to the messagedistributor to warn the |
2012 | * modeller that some conditions required by the framework are not met. Be |
2013 | * sure to have a correct location, since the object and method that the |
2014 | * error becomes apparent is not necessary the location it was produced in. |
2015 | * The information about the simulation time is extracted from the |
2016 | * experiment and must not be given as a parameter. |
2017 | * |
2018 | * @param description |
2019 | * java.lang.String : The description of the error that occured |
2020 | * @param location |
2021 | * java.lang.String : The class and method the error occured in |
2022 | * @param reason |
2023 | * java.lang.String : The reason most probably responsible for |
2024 | * the error to occur |
2025 | * @param prevention |
2026 | * java.lang.String : The measures a user should take to prevent |
2027 | * this warning to be issued again |
2028 | */ |
2029 | void sendWarning(String description, String location, String reason, |
2030 | String prevention) { |
2031 | |
2032 | // comnpose the WarningMessage and send it in one command |
2033 | sendMessage(new ErrorMessage(clientScheduler.getCurrentModel(), |
2034 | description, location, reason, prevention, clientScheduler |
2035 | .getSimClock().getTime())); |
2036 | |
2037 | } |
2038 | |
2039 | /** |
2040 | * Sets the TimeFormatter to be used for output of time Strings. |
2041 | * |
2042 | * @param format |
2043 | * TimeFormatter : the formatter to be used for formatting time |
2044 | * Strings. |
2045 | * |
2046 | */ |
2047 | public void setTimeFormatter(TimeFormatter format) { |
2048 | TimeOperations.setTimeFormatter(format); |
2049 | } |
2050 | |
2051 | /** |
2052 | * Determines if the event-list processes concurrent Events in random order |
2053 | * or not. Default is not, i.e. when a new experiment is constructed, the |
2054 | * event-list is set to "linear" order. Note: If you want the event-list to |
2055 | * randomize concurrent Events you should call this method BEFORE scheduling |
2056 | * any events. Otherwise any connections between events established via |
2057 | * scheduleBefore() or scheduleAfter() are lost. So it's a good idea to call |
2058 | * this method only once and right after constructing the experiment. |
2059 | * |
2060 | * @param randomizing |
2061 | * boolean :<code>true</code> forces random order, |
2062 | * <code>false</code> forces "linear" order |
2063 | * @author Ruth Meyer |
2064 | */ |
2065 | public void randomizeConcurrentEvents(boolean randomizing) { |
2066 | clientScheduler.setRandomizingConcurrentEvents(randomizing); |
2067 | } |
2068 | |
2069 | /** |
2070 | * Sets the speed rate for an execution that is proportional to wall-clock |
2071 | * time (real time). Set the speed rate to a value bigger than zero for a |
2072 | * simulation that will progress proportional to wall-clock time. The |
2073 | * following equation applies for speed rates >0 : rate*simulation time = |
2074 | * wallclock-time. If the speed rate is 0 or less the simulation will be |
2075 | * executed as fast as possible. Default is 0 (as-fast-as-possible). |
2076 | * |
2077 | * @param rate |
2078 | * double : The execution speed rate |
2079 | */ |
2080 | public void setExecutionSpeedRate(double rate) { |
2081 | clientScheduler.setExecutionSpeedRate(rate); |
2082 | } |
2083 | |
2084 | /** |
2085 | * Sets the seed of the SeedGenerator to the given value. If the seed is not |
2086 | * set here, its default is 979, unless specified different in the |
2087 | * ExperimentOptions. |
2088 | * |
2089 | * @param seed |
2090 | * long : The seed for the SeedGenerator |
2091 | */ |
2092 | public void setSeedGenerator(long seed) { |
2093 | |
2094 | _distMan.setSeed(seed); |
2095 | |
2096 | } |
2097 | |
2098 | /** |
2099 | * Sets the underlying pseudo random number generator to be used by all |
2100 | * distributions created from now on. The default generator is |
2101 | * LinearCongruentialRandomGenerator; any other generator to be used must |
2102 | * implement the interface UniformRandomGenerator. |
2103 | * |
2104 | * @see desmoj.core.dist.LinearCongruentialRandomGenerator |
2105 | * @see desmoj.core.dist.UniformRandomGenerator |
2106 | * |
2107 | * @param randomNumberGenerator |
2108 | * Class : The random number generator class to be used |
2109 | */ |
2110 | public void setRandomNumberGenerator( |
2111 | Class<? extends desmoj.core.dist.UniformRandomGenerator> randomNumberGenerator) { |
2112 | |
2113 | boolean classValid = false; |
2114 | // // Verify that a class implementing interface |
2115 | // desmoj.desmoj.core.dist.UniformRandomGenerator was passed |
2116 | // for (int i = 0; i < randomNumberGenerator.getInterfaces().length; |
2117 | // i++) { |
2118 | // if |
2119 | // (randomNumberGenerator.getInterfaces()[i].equals(desmoj.core.dist.UniformRandomGenerator.class)) |
2120 | // { |
2121 | // classValid = true; |
2122 | // break; |
2123 | // } |
2124 | // } |
2125 | |
2126 | // Verify the class provided is not abstract |
2127 | if ((randomNumberGenerator.getModifiers() & java.lang.reflect.Modifier.ABSTRACT) > 0 |
2128 | || (randomNumberGenerator.getModifiers() & java.lang.reflect.Modifier.INTERFACE) > 0) |
2129 | classValid = false; |
2130 | |
2131 | // Update the random number generator... |
2132 | if (classValid) { |
2133 | |
2134 | this._distMan.setRandomNumberGenerator(randomNumberGenerator); |
2135 | |
2136 | // ...or otherwise return an error |
2137 | } else { |
2138 | |
2139 | this |
2140 | .sendWarning( |
2141 | "Invalid random number generator given! Method call ignored!", |
2142 | "Experiment '" |
2143 | + getName() |
2144 | + "', Method 'setRandomNumberGenerator(Class randomNumberGenerator)'", |
2145 | "The class provided '" |
2146 | + randomNumberGenerator.getSimpleName() |
2147 | + "' is abstract or does not implement the interface" |
2148 | + " desmoj.desmoj.core.dist.UniformRandomGenerator.", |
2149 | "Make sure to use a non-abstract class that implements the interface" |
2150 | + " desmoj.desmoj.core.dist.UniformRandomGenerator."); |
2151 | } |
2152 | } |
2153 | |
2154 | /** |
2155 | * Sets the new value for showing the progress bar for this experiment or |
2156 | * not. |
2157 | * |
2158 | * @param newShowProgressBar |
2159 | * boolean : set it to <code>true</code> if a progress bar should |
2160 | * be displayed; for not showing the progress bar of this |
2161 | * experiment set it to <code>false</code>. |
2162 | */ |
2163 | public void setShowProgressBar(boolean newShowProgressBar) { |
2164 | |
2165 | this._showProgressBar = newShowProgressBar; |
2166 | } |
2167 | |
2168 | /** |
2169 | * Sets the new value for displaying basic experiment notifications like |
2170 | * 'experiment started', 'experiment stopped' oder 'experiment resumed' |
2171 | * at the system output. |
2172 | * |
2173 | * @param silent |
2174 | * boolean : set it to <code>true</code> to suppress notifications |
2175 | * or <code>false</code> to print them. |
2176 | */ |
2177 | public void setSilent(boolean silent) { |
2178 | |
2179 | this._silent = silent; |
2180 | } |
2181 | |
2182 | /** |
2183 | * Sets the experiment's status to the given integer value. The value must |
2184 | * be in the legal range of [-1,5], otherwise a warning is issued. |
2185 | * |
2186 | * @param newStatus |
2187 | * int : The integer value of the experiments' new status |
2188 | */ |
2189 | void setStatus(int newStatus) { |
2190 | |
2191 | if ((newStatus < -1) || (newStatus > 5)) { |
2192 | sendWarning( |
2193 | "Can not start experiment! Command ignored.", |
2194 | "Experiment '" + getName() + "', Method 'start'", |
2195 | "No main model's connectToExperiment(Experiment e) method was called.", |
2196 | "Make sure to connect a valid main model first before starting " |
2197 | + "this experiment."); |
2198 | return; |
2199 | } else |
2200 | _status = newStatus; |
2201 | |
2202 | } |
2203 | |
2204 | /** |
2205 | * Starts the simulation with default start time 0. This method can only be |
2206 | * used once on an experiment. it initializes the connected model and starts |
2207 | * the simulation. Note that in order to stop the simulation, the |
2208 | * <code>stop(TimeInstant stopTime)</code> method has to be called first! |
2209 | */ |
2210 | public void start() { |
2211 | |
2212 | // this allows us to use start() in loops for multiple experiment runs |
2213 | // in other words, this is a shortcut for the lazy programmer |
2214 | if (_status == STOPPED) |
2215 | proceed(); |
2216 | |
2217 | // here's what start was supposed to be at first |
2218 | // a shortcut for startig an Experiment at TimeInstant(0) |
2219 | else { |
2220 | // now prepare connected model to start simulation |
2221 | start(new TimeInstant(0)); |
2222 | } |
2223 | |
2224 | } |
2225 | |
2226 | /** |
2227 | * Starts the experiment with the given simulation time as starting time. |
2228 | * The experiment will not start unless a valid model has been connected to |
2229 | * it before. Note that in order to stop the simulation at some point of |
2230 | * time, the <code>stop</code> method has to be called first. |
2231 | * <code>StopCondition</code> s can be given alternatively. |
2232 | * |
2233 | * @param initTime |
2234 | * TimeInstant : The starting time instant |
2235 | */ |
2236 | public void start(TimeInstant initTime) { |
2237 | |
2238 | if (_status < CONNECTED) { |
2239 | sendWarning( |
2240 | "Can not start experiment! Command ignored.", |
2241 | "Experiment: " + getName() |
2242 | + " Method: void start(SimTime initTime)", |
2243 | "The Experiment has not been connected to a model to report about yet.", |
2244 | "Connect a model to the experiment first using the model's method " |
2245 | + "connectToExperiment(Experiment exp)."); |
2246 | return; |
2247 | } |
2248 | if (_status > CONNECTED) { |
2249 | sendWarning( |
2250 | "Can not start experiment! Command ignored.", |
2251 | "Experiment: " + getName() |
2252 | + " Method: void start(SimTime initTime)", |
2253 | "The Experiment has already been started before.", |
2254 | "An experiment can only be started once. If it has been stopped, " |
2255 | + "it can be issued to continue using method proceed()"); |
2256 | return; |
2257 | } |
2258 | |
2259 | // check initial TimeInstant parameter |
2260 | if (initTime != null) { |
2261 | clientScheduler.getSimClock().setInitTime(initTime); |
2262 | if(!TimeInstant.isEqual(initTime,new TimeInstant(0))){ |
2263 | _client.reset(); |
2264 | } |
2265 | } else { |
2266 | clientScheduler.getSimClock().setTime(new TimeInstant(0)); |
2267 | sendWarning( |
2268 | "Invalid start time parameter given! Start time set to " |
2269 | + clientScheduler.presentTime() + ".", |
2270 | "Experiment: '" + getName() |
2271 | + "', Method: void start(SimTime initTime)", |
2272 | "A null calue or a not initialized TimeInstant reference has been passed.", |
2273 | "Make sure to have a valid TimeInstnat object, otherwise use method " |
2274 | + "start() without TimeInstant parameter."); |
2275 | } |
2276 | |
2277 | // client.init(); already done in connectToExperiment |
2278 | _client.doInitialSchedules(); |
2279 | _client.doSubmodelSchedules(); |
2280 | TimeOperations.setStartTime(initTime); |
2281 | // now everything is set up, go on and process events |
2282 | _status = STARTED; |
2283 | this._realTimeStartTime = System.nanoTime(); |
2284 | |
2285 | proceed(); |
2286 | |
2287 | } |
2288 | |
2289 | /** |
2290 | * @deprecated Use start(TimeInstant initTime). |
2291 | * Starts the experiment with the given simulation time as starting time. |
2292 | * The experiment will not start unless a valid model has been connected to |
2293 | * it before. Note that in order to stop the simulation at some point of |
2294 | * time, the <code>stop</code> method has to be called first. |
2295 | * <code>StopCondition</code> s can be given alternatively. |
2296 | * |
2297 | * @param initTime |
2298 | * TimeInstant : The starting time instant |
2299 | */ |
2300 | public void start(SimTime initTime) { |
2301 | start(SimTime.toTimeInstant(initTime)); |
2302 | } |
2303 | |
2304 | /** |
2305 | * Specifies a ModelCondition to stop the simulation. Note that this methode can |
2306 | * be called muliple times, defining alternative conditions to terminate the |
2307 | * simulation. Once at least one of the conditions passed using this method |
2308 | * returns true, the experiment will stop. |
2309 | * Beware that the simulation will run endlessly if none of the conditions |
2310 | * are met; thus it is recommended to additionally always use a time limit |
2311 | * if none of the conditions in question can be proven to be met during the |
2312 | * run of the simulation! |
2313 | * |
2314 | * @param stopCond |
2315 | * ModelCondition : A condition to stop the simulation once |
2316 | * it's check() methode returns true. |
2317 | */ |
2318 | public void stop(ModelCondition stopCond) { |
2319 | |
2320 | if (stopCond == null) { |
2321 | sendWarning("Can not set stop-condition! Command ignored.", |
2322 | "Experiment '" + getName() |
2323 | + "', Method 'stop(Condition stopCond)'", |
2324 | "The parameter passed was either null or a not initialized " |
2325 | + "Condition reference.", |
2326 | "Make sure to provide a valid stop Condition for " |
2327 | + "this experiment."); |
2328 | } else { |
2329 | this._stopConditions.add(stopCond); |
2330 | } |
2331 | |
2332 | } |
2333 | |
2334 | @Deprecated |
2335 | /** |
2336 | * @deprecated Replaced by <code>stop(ModelCondition stopCond)</code> |
2337 | * |
2338 | * Specifies a Condition to stop the simulation. |
2339 | * |
2340 | * @param stopCond |
2341 | * Condition<?> : A condition to stop the simulation once |
2342 | * it's check() methode returns true. |
2343 | */ |
2344 | public void stop(Condition<?> stopCond) { |
2345 | |
2346 | if (stopCond == null) { |
2347 | sendWarning("Can not set stop-condition! Command ignored.", |
2348 | "Experiment '" + getName() |
2349 | + "', Method 'stop(Condition stopCond)'", |
2350 | "The parameter passed was either null or a not initialized " |
2351 | + "Condition reference.", |
2352 | "Make sure to provide a valid stop Condition for " |
2353 | + "this experiment."); |
2354 | } else { |
2355 | this.stop(new ModelCondition.ConditionWrapper(this.getModel(), stopCond)); |
2356 | } |
2357 | |
2358 | } |
2359 | |
2360 | /** |
2361 | * Stops the simulation at the given point of simulation time. If no valid |
2362 | * simulation time is given, the default is 0 which would not |
2363 | * let the simulation run past that time. Repeatedly calling this method |
2364 | * will override stop times specified before. |
2365 | * |
2366 | * @param stopTime |
2367 | * desmoj.TimeInstant : The point of simulation time to stop the |
2368 | * simulation |
2369 | */ |
2370 | public void stop(TimeInstant stopTime) { |
2371 | if (stopTime == null) { |
2372 | sendWarning( |
2373 | "Can not set stop-time! The stop-time will be set to 0", |
2374 | "Experiment '" + getName() |
2375 | + "', Method: 'stop(TimeInstant stopTime)'", |
2376 | "The parameter passed was either null or a not initialized " |
2377 | + "TimeInstance reference.", |
2378 | "Pass an initialized TimeInstant object as stop time."); |
2379 | |
2380 | ExternalEventStop stopper = new ExternalEventStop(_client, |
2381 | "Simulation stopped", true); |
2382 | stopper.schedule(new TimeInstant(0)); |
2383 | |
2384 | } else { |
2385 | |
2386 | this._stopTime = stopTime; |
2387 | if (this._stopTimeEvent != null) this._stopTimeEvent.cancel(); |
2388 | |
2389 | this._stopTimeEvent = new ExternalEventStop(_client, "Simulation stopped", true); |
2390 | _stopTimeEvent.schedule(stopTime); |
2391 | } |
2392 | } |
2393 | |
2394 | /** |
2395 | * @deprecated Stops the simulation at the given point of simulation time. |
2396 | * If no valid simulation time is given, the default is 0.0 |
2397 | * which would not let the simulation run past that time. |
2398 | * |
2399 | * @param stopTime |
2400 | * desmoj.SimTime : The point of simulation time to stop the |
2401 | * simulation |
2402 | */ |
2403 | @Deprecated |
2404 | public void stop(SimTime stopTime) { |
2405 | stop(SimTime.toTimeInstant(stopTime)); |
2406 | } |
2407 | |
2408 | /** |
2409 | * Stops the simulation at the current simulation time (immediately). A |
2410 | * stopped Simulation run can be resumed by calling proceed(). |
2411 | */ |
2412 | public void stop() { |
2413 | setStatus(STOPPED); |
2414 | clientScheduler.signalStop(); |
2415 | } |
2416 | |
2417 | /** |
2418 | * Returns a boolean indicating whether trace notes are forwarded to the |
2419 | * trace ouput or not. Trace ouput can be switched on and off using the |
2420 | * methods <code>traceOn(TimeInstant startTime)</code> and |
2421 | * <code>traceOff(TimeInstant stopTime)</code> |
2422 | * |
2423 | * @return boolean : Is <code>true</code> |
2424 | */ |
2425 | public boolean traceIsOn() { |
2426 | |
2427 | return _messMan.isOn(tracenote); |
2428 | |
2429 | } |
2430 | |
2431 | /** |
2432 | * Switches the trace output off at the given point of simulation time. |
2433 | * |
2434 | * @param stopTime |
2435 | * TimeInstant : The point in simulation time to switch trace off |
2436 | */ |
2437 | public void traceOff(TimeInstant stopTime) { |
2438 | |
2439 | // check initial TimeInstant parameter |
2440 | if (stopTime == null) { |
2441 | sendWarning( |
2442 | "Invalid start time parameter for trace output given! " |
2443 | + "Trace output is set to start immediately.", |
2444 | "Experiment '" + getName() |
2445 | + "', Method 'traceOn(TimeInstant startTime)'", |
2446 | "A null value or a not initialized TimeInstant reference has been passed.", |
2447 | "Make sure to have a valid TimeInstant object, otherwise use method " |
2448 | + "start() without TimeInstant parameter."); |
2449 | stopTime = clientScheduler.presentTime(); |
2450 | } |
2451 | |
2452 | // check if parameter is in future |
2453 | if (TimeInstant.isAfter(clientScheduler.presentTime(), stopTime)) { |
2454 | sendWarning("Invalid start time parameter for trace output given! " |
2455 | + "Trace output is set to start immediately.", |
2456 | "Experiment '" + getName() |
2457 | + "', Method 'traceOn(TimeInstant stopTime)'", |
2458 | "The stopTime given is in the past.", |
2459 | "Make sure to give a TimeInstant parameter larger than the current time."); |
2460 | stopTime = clientScheduler.presentTime(); |
2461 | } |
2462 | |
2463 | ExternalEvent traceOff = new ExternalEventTraceOff(_client, true); |
2464 | traceOff.schedule(stopTime); |
2465 | } |
2466 | |
2467 | /** |
2468 | * @deprecated Use traceOff(TimeInstant startTime). Switches the trace output off at the given point of simulation time. |
2469 | * |
2470 | * @param stopTime |
2471 | * SimTime : The point in simulation time to switch trace off |
2472 | */ |
2473 | public void traceOff(SimTime stopTime) { |
2474 | this.traceOff(SimTime.toTimeInstant(stopTime)); |
2475 | } |
2476 | |
2477 | /** |
2478 | * Switches the trace output on at the given point of simulation time. |
2479 | * |
2480 | * @param startTime |
2481 | * TimeInstant : The point in simulation time to switch trace on |
2482 | */ |
2483 | public void traceOn(TimeInstant startTime) { |
2484 | |
2485 | // check initial TimeInstant parameter |
2486 | if (startTime == null) { |
2487 | sendWarning( |
2488 | "Invalid start time parameter for trace output given! " |
2489 | + "Trace output is set to start immediately.", |
2490 | "Experiment '" + getName() |
2491 | + "', Method 'traceOn(TimeInstant startTime)'", |
2492 | "A null value or a not initialized TimeInstant reference has been passed.", |
2493 | "Make sure to have a valid TimeInstant object, otherwise use method " |
2494 | + "start() without TimeInstant parameter."); |
2495 | startTime = clientScheduler.presentTime(); |
2496 | } |
2497 | |
2498 | // check if parameter is in future |
2499 | if (TimeInstant.isAfter(clientScheduler.presentTime(), startTime)) { |
2500 | sendWarning("Invalid start time parameter for trace output given! " |
2501 | + "Trace output is set to start immediately.", |
2502 | "Experiment '" + getName() |
2503 | + "', Method 'traceOn(TimeInstant startTime)'", |
2504 | "The startTime given is in the past.", |
2505 | "Make sure to give a TimeInstant parameter larger than the current time."); |
2506 | startTime = clientScheduler.presentTime(); |
2507 | } |
2508 | |
2509 | // if parameter equals current time, set trace on immediately, e.g. |
2510 | // to include initial scheduling |
2511 | if (TimeInstant.isEqual(clientScheduler.presentTime(), startTime)) { |
2512 | this.getMessageManager().switchOn(Experiment.tracenote); |
2513 | _client.sendTraceNote("Trace switched on"); |
2514 | // Otherwise schedule an appropriate event |
2515 | } else { |
2516 | ExternalEvent traceOn = new ExternalEventTraceOn(_client, true); |
2517 | traceOn.schedule(startTime); |
2518 | } |
2519 | |
2520 | } |
2521 | |
2522 | /** |
2523 | * @deprecated Use traceOn(TimeInstant startTime). Switches the trace output on at the given point of simulation time. |
2524 | * |
2525 | * @param startTime |
2526 | * SimTime : The point in simulation time to switch trace on |
2527 | */ |
2528 | public void traceOn(SimTime startTime) { |
2529 | this.traceOn(SimTime.toTimeInstant(startTime)); |
2530 | } |
2531 | |
2532 | /** |
2533 | * Switches the trace output on for the given period of simulation time. If |
2534 | * the second parameter (off) is "sooner" then the first parameter (on), |
2535 | * they will be swapped automatically. Same parameters will result in no |
2536 | * trace output at all. |
2537 | * |
2538 | * @param startTime |
2539 | * TimeInstant : The point in simulation time to switch trace on |
2540 | * @param stopTime |
2541 | * TimeInstant : The point in simulation time to switch trace off |
2542 | */ |
2543 | public void tracePeriod(TimeInstant startTime, TimeInstant stopTime) { |
2544 | if (startTime == null) { |
2545 | sendWarning( |
2546 | "Invalid start time parameter for trace output given! Command ignored", |
2547 | "Experiment '" + getName() |
2548 | + "', Method 'tracePeriod(TimeInstant startTime, " |
2549 | + "TimeInstant stopTime)'", |
2550 | "A null value or a not initialized TimeInstant reference has been passed.", |
2551 | "Make sure to have a valid TimeInstant object."); |
2552 | return; |
2553 | } |
2554 | |
2555 | // check initial TimeInstant parameter |
2556 | if (stopTime == null) { |
2557 | sendWarning( |
2558 | "Invalid stop time parameter for trace output given! Command ignored.", |
2559 | "Experiment '" + getName() |
2560 | + "', Method 'tracePeriod(TimeInstant startTime, " |
2561 | + "TimeInstant stopTime)'", |
2562 | "A null value or a not initialized TimeInstant reference has been passed.", |
2563 | "Make sure to have a valid TimeInstant object."); |
2564 | return; |
2565 | } |
2566 | |
2567 | // check for correct order in parameters |
2568 | if (TimeInstant.isAfter(startTime, stopTime)) { |
2569 | |
2570 | // swap parameters |
2571 | TimeInstant buffer = stopTime; |
2572 | stopTime = startTime; |
2573 | startTime = buffer; |
2574 | |
2575 | } |
2576 | |
2577 | // check if stop parameter is in future |
2578 | if (TimeInstant.isAfter(clientScheduler.presentTime(), stopTime)) { |
2579 | sendWarning( |
2580 | "Invalid stop time parameter for trace output given! Command ignored.", |
2581 | "Experiment '" + getName() |
2582 | + "', Method 'tracePeriod(TimeInstant startTime, " |
2583 | + "TimeInstant stopTime)'", |
2584 | "The stopTime given is in the past.", |
2585 | "Make sure to give a TimeInstant parameter larger than the current time."); |
2586 | return; |
2587 | } |
2588 | |
2589 | // check if start parameter is in past |
2590 | if (TimeInstant.isAfter(clientScheduler.presentTime(), startTime)) { |
2591 | sendWarning("Invalid start time parameter for trace output given! " |
2592 | + "Trace output has been set to start immediately.", |
2593 | "Experiment '" + getName() |
2594 | + "', Method 'tracePeriod(TimeInstant startTime, " |
2595 | + "TimeInstant startTime)'", |
2596 | "The startTime given is in the past.", |
2597 | "Make sure to give a TimeInstant parameter larger than the current time."); |
2598 | startTime = clientScheduler.presentTime(); |
2599 | } |
2600 | |
2601 | // set trace to switch on |
2602 | traceOn(startTime); |
2603 | |
2604 | // set trace to switch off |
2605 | traceOff(stopTime); |
2606 | } |
2607 | |
2608 | /** |
2609 | * @deprecated Replaced by tracePeriod(TimeInstant startTime, TimeInstant |
2610 | * stopTime). Switches the trace output on for the given period |
2611 | * of simulation time. If the second parameter (off) is "sooner" |
2612 | * then the first parameter (on), they will be swapped |
2613 | * automatically. Same parameters will result in no trace output |
2614 | * at all. |
2615 | * |
2616 | * @param startTime |
2617 | * SimTime : The point in simulation time to switch trace on |
2618 | * @param stopTime |
2619 | * SimTime : The point in simulation time to switch trace off |
2620 | */ |
2621 | @Deprecated |
2622 | public void tracePeriod(SimTime startTime, SimTime stopTime) { |
2623 | tracePeriod(SimTime.toTimeInstant(startTime), SimTime |
2624 | .toTimeInstant(stopTime)); |
2625 | } |
2626 | |
2627 | /** |
2628 | * Triggers the reporters of the given model or submodel to write their |
2629 | * report data into the report output registered at the experiment's |
2630 | * messagemanager. The string given will be added as a suffix to the report |
2631 | * filename to help identify teh report when more than one report is |
2632 | * produced by one Experiment at differnet points of simulation time. |
2633 | * |
2634 | * @param m |
2635 | * desmoj.Model |
2636 | * @param suffix |
2637 | * java.lang.String : Suffix for report filename if multiple |
2638 | * reports are drawn |
2639 | */ |
2640 | public void writeReport(Model m, String suffix) { |
2641 | |
2642 | if (suffix == null) |
2643 | suffix = ""; |
2644 | |
2645 | // buffer used for storing the filename in |
2646 | String nameBuffer = null; |
2647 | |
2648 | // now flush and close all files and reopen with new names |
2649 | for (FileOutput f : _registryFileOutput) { |
2650 | |
2651 | // remember the name the file had |
2652 | nameBuffer = f.getFileName(); |
2653 | |
2654 | // flush buffer and close file |
2655 | f.close(); |
2656 | |
2657 | // open new file with old name stripping off old suffix and |
2658 | // adding new suffix |
2659 | nameBuffer = nameBuffer.substring(0, nameBuffer.lastIndexOf(".")); |
2660 | f.open(nameBuffer.substring(0, (nameBuffer.length() - lastSuffix)) |
2661 | + suffix + "html"); |
2662 | } |
2663 | lastSuffix = suffix.length(); // remember last suffix length |
2664 | report(m); |
2665 | } |
2666 | |
2667 | /** |
2668 | * Triggers the reporters to write their data into the report output |
2669 | * registered at the experiment's messagemanager. The string given will be |
2670 | * added as a suffix to the report filename to help identification when more |
2671 | * than one report is produced by one Experiment at differnet points of |
2672 | * simulation time. |
2673 | * |
2674 | * @param suffix |
2675 | * java.lang.String : Suffix for report filename if multiple |
2676 | * reports are drawn |
2677 | */ |
2678 | public void writeReport(String suffix) { |
2679 | |
2680 | if (suffix == null) |
2681 | suffix = ""; |
2682 | |
2683 | // write report data about main model |
2684 | report(_client); |
2685 | |
2686 | // buffer used for storing the filename in |
2687 | String nameBuffer = null; |
2688 | |
2689 | // now flush and close all files and reopen with new names |
2690 | for (FileOutput f : _registryFileOutput) { |
2691 | |
2692 | // remember the name the file had |
2693 | nameBuffer = f.getFileName(); |
2694 | |
2695 | // flush buffer and close file |
2696 | f.close(); |
2697 | |
2698 | // open new file with old name stripping off old suffix and |
2699 | // adding new suffix |
2700 | // strip the _debug / _error / _trace / _report part |
2701 | nameBuffer = nameBuffer.substring(0, nameBuffer.lastIndexOf("_")); |
2702 | // strip the previous suffix |
2703 | nameBuffer = nameBuffer.substring(0, nameBuffer.length() |
2704 | - lastSuffix); |
2705 | // add new suffix |
2706 | nameBuffer = nameBuffer + suffix; |
2707 | // now open file with new name |
2708 | f.open(nameBuffer); |
2709 | } |
2710 | lastSuffix = suffix.length(); // remember last suffix length |
2711 | } |
2712 | |
2713 | /** |
2714 | * Returns the current DESMO-J version |
2715 | * |
2716 | * @return The string "2.3.3". |
2717 | */ |
2718 | public static String getDesmoJVersion() { |
2719 | return "2.3.3"; |
2720 | } |
2721 | |
2722 | /** |
2723 | * Returns the DESMO-J license |
2724 | * |
2725 | * @param html |
2726 | * boolean: Include link (HTML, true) or not (plain text, false) |
2727 | * |
2728 | * @return The string "Apache License, Version 2.0", embedded in a HTML link |
2729 | * tag (currently http://www.apache.org/licenses/LICENSE-2.0) if |
2730 | * <code>html</code> is set true. |
2731 | */ |
2732 | public static String getDesmoJLicense(boolean html) { |
2733 | return html ? "<A HREF=http://www.apache.org/licenses/LICENSE-2.0>Apache License, Version 2.0</A>" |
2734 | : "Apache License, Version 2.0"; |
2735 | } |
2736 | |
2737 | public void setDescription(String description) { |
2738 | this._description = description; |
2739 | } |
2740 | |
2741 | public String getDescription() { |
2742 | return _description; |
2743 | } |
2744 | } |