1 package org.opentrafficsim.swing.script;
2
3 import java.awt.Dimension;
4 import java.rmi.RemoteException;
5 import java.text.SimpleDateFormat;
6 import java.util.Date;
7 import java.util.LinkedHashMap;
8 import java.util.List;
9 import java.util.Map;
10
11 import org.djunits.value.vdouble.scalar.Duration;
12 import org.djunits.value.vdouble.scalar.Time;
13 import org.djutils.cli.Checkable;
14 import org.djutils.cli.CliException;
15 import org.djutils.cli.CliUtil;
16 import org.djutils.event.EventInterface;
17 import org.djutils.event.EventListenerInterface;
18 import org.djutils.exceptions.Throw;
19 import org.djutils.exceptions.Try;
20 import org.djutils.reflection.ClassUtil;
21 import org.opentrafficsim.core.animation.gtu.colorer.GTUColorer;
22 import org.opentrafficsim.core.dsol.OTSAnimator;
23 import org.opentrafficsim.core.dsol.OTSModelInterface;
24 import org.opentrafficsim.core.dsol.OTSSimulator;
25 import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
26 import org.opentrafficsim.core.network.OTSNetwork;
27 import org.opentrafficsim.draw.core.OTSDrawingException;
28 import org.opentrafficsim.draw.factory.DefaultAnimationFactory;
29 import org.opentrafficsim.road.network.OTSRoadNetwork;
30 import org.opentrafficsim.swing.gui.AnimationToggles;
31 import org.opentrafficsim.swing.gui.OTSAnimationPanel;
32 import org.opentrafficsim.swing.gui.OTSSimulationApplication;
33 import org.opentrafficsim.swing.gui.OTSSwingApplication;
34
35 import nl.tudelft.simulation.dsol.SimRuntimeException;
36 import nl.tudelft.simulation.dsol.experiment.ReplicationInterface;
37 import nl.tudelft.simulation.dsol.experiment.StreamInformation;
38 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterMap;
39 import nl.tudelft.simulation.dsol.simtime.SimTimeDoubleUnit;
40 import nl.tudelft.simulation.dsol.statistics.StatisticsInterface;
41 import nl.tudelft.simulation.jstats.streams.MersenneTwister;
42 import nl.tudelft.simulation.jstats.streams.StreamInterface;
43 import picocli.CommandLine.Command;
44 import picocli.CommandLine.Option;
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 @Command(description = "Test program for CLI", name = "Program", mixinStandardHelpOptions = true, showDefaultValues = true)
61 public abstract class AbstractSimulationScript implements EventListenerInterface, Checkable
62 {
63
64 private static final long serialVersionUID = 20200129L;
65
66
67 private final String name;
68
69
70 private final String description;
71
72
73 private OTSSimulatorInterface simulator;
74
75
76 private OTSRoadNetwork network;
77
78
79 private GTUColorer gtuColorer = OTSSwingApplication.DEFAULT_COLORER;
80
81
82 @Option(names = "--seed", description = "Seed", defaultValue = "1")
83 private long seed;
84
85
86 @Option(names = { "-s", "--startTime" }, description = "Start time", defaultValue = "0s")
87 private Time startTime;
88
89
90 @Option(names = { "-w", "--warmupTime" }, description = "Warm-up time", defaultValue = "0s")
91 private Duration warmupTime;
92
93
94 @Option(names = { "-t", "--simulationTime" }, description = "Simulation time (including warm-up time)",
95 defaultValue = "3600s")
96 private Duration simulationTime;
97
98
99 @Option(names = { "-a", "--autorun" }, description = "Autorun", negatable = true, defaultValue = "false")
100 private boolean autorun;
101
102
103
104
105
106
107 protected AbstractSimulationScript(final String name, final String description)
108 {
109 this.name = name;
110 this.description = description;
111 try
112 {
113 CliUtil.changeCommandName(this, this.name);
114 CliUtil.changeCommandDescription(this, this.description);
115 SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
116 CliUtil.changeCommandVersion(this,
117 formatter.format(new Date(ClassUtil.classFileDescriptor(this.getClass()).getLastChangedDate())));
118 }
119 catch (IllegalStateException | IllegalArgumentException | CliException exception)
120 {
121 throw new RuntimeException("Exception while setting properties in @Command annotation.", exception);
122 }
123 }
124
125
126
127
128
129 public long getSeed()
130 {
131 return this.seed;
132 }
133
134
135
136
137
138 public Time getStartTime()
139 {
140 return this.startTime;
141 }
142
143
144
145
146
147 public Duration getWarmupTime()
148 {
149 return this.warmupTime;
150 }
151
152
153
154
155
156 public Duration getSimulationTime()
157 {
158 return this.simulationTime;
159 }
160
161
162
163
164
165 public boolean isAutorun()
166 {
167 return this.autorun;
168 }
169
170
171
172
173
174 public final void setGtuColorer(final GTUColorer colorer)
175 {
176 this.gtuColorer = colorer;
177 }
178
179
180
181
182
183 public final GTUColorer getGtuColorer()
184 {
185 return this.gtuColorer;
186 }
187
188
189 @Override
190 public void check() throws Exception
191 {
192 Throw.when(this.seed < 0, IllegalArgumentException.class, "Seed should be positive");
193 Throw.when(this.warmupTime.si < 0.0, IllegalArgumentException.class, "Warm-up time should be positive");
194 Throw.when(this.simulationTime.si < 0.0, IllegalArgumentException.class, "Simulation time should be positive");
195 Throw.when(this.simulationTime.si < this.warmupTime.si, IllegalArgumentException.class,
196 "Simulation time should be longer than warmp-up time");
197 }
198
199
200
201
202
203 public final void start() throws Exception
204 {
205 if (isAutorun())
206 {
207
208 this.simulator = new OTSSimulator(this.name);
209 final ScriptModel scriptModel = new ScriptModel(this.simulator);
210 this.simulator.initialize(this.startTime, this.warmupTime, this.simulationTime, scriptModel);
211 this.simulator.addListener(this, ReplicationInterface.END_REPLICATION_EVENT);
212 double tReport = 60.0;
213 Time t = this.simulator.getSimulatorTime();
214 while (t.si < this.simulationTime.si)
215 {
216 this.simulator.step();
217 t = this.simulator.getSimulatorTime();
218 if (t.si >= tReport)
219 {
220 System.out.println("Simulation time is " + t);
221 tReport += 60.0;
222 }
223 }
224
225 onSimulationEnd();
226 System.exit(0);
227 }
228 else
229 {
230 this.simulator = new OTSAnimator(this.name);
231 final ScriptModel scriptModel = new ScriptModel(this.simulator);
232 this.simulator.initialize(this.startTime, this.warmupTime, this.simulationTime, scriptModel);
233 OTSAnimationPanel animationPanel =
234 new OTSAnimationPanel(scriptModel.getNetwork().getExtent(), new Dimension(800, 600),
235 (OTSAnimator) this.simulator, scriptModel, getGtuColorer(), scriptModel.getNetwork());
236 setAnimationToggles(animationPanel);
237 animateNetwork(scriptModel.getNetwork());
238 setupDemo(animationPanel, scriptModel.getNetwork());
239 OTSSimulationApplication<ScriptModel> app = new OTSSimulationApplication<ScriptModel>(scriptModel, animationPanel)
240 {
241
242 private static final long serialVersionUID = 20190130L;
243
244
245 @Override
246 protected void animateNetwork() throws OTSDrawingException
247 {
248
249 }
250
251
252 @Override
253 protected void setAnimationToggles()
254 {
255
256 }
257 };
258 addTabs(this.simulator, app);
259 app.setExitOnClose(true);
260 animationPanel.enableSimulationControlButtons();
261 }
262 }
263
264
265 @Override
266 public void notify(final EventInterface event) throws RemoteException
267 {
268 if (event.getType().equals(ReplicationInterface.END_REPLICATION_EVENT))
269 {
270
271
272
273
274
275
276
277
278 onSimulationEnd();
279
280 AbstractSimulationScript.this.simulator.removeListener(AbstractSimulationScript.this,
281 ReplicationInterface.END_REPLICATION_EVENT);
282 }
283 }
284
285
286
287
288
289 public final OTSSimulatorInterface getSimulator()
290 {
291 return AbstractSimulationScript.this.simulator;
292 }
293
294
295
296
297
298 public final OTSRoadNetwork getNetwork()
299 {
300 return AbstractSimulationScript.this.network;
301 }
302
303
304
305
306
307
308
309 protected void animateNetwork(final OTSNetwork net)
310 {
311 try
312 {
313 DefaultAnimationFactory.animateNetwork(net, net.getSimulator(), getGtuColorer());
314 }
315 catch (OTSDrawingException exception)
316 {
317 throw new RuntimeException("Exception while creating network animation.", exception);
318 }
319 }
320
321
322
323
324
325
326 protected void addTabs(final OTSSimulatorInterface sim, final OTSSimulationApplication<?> animation)
327 {
328
329 }
330
331
332
333
334 protected void onSimulationEnd()
335 {
336
337 }
338
339
340
341
342
343
344 protected void setupDemo(final OTSAnimationPanel animationPanel, final OTSRoadNetwork net)
345 {
346
347 }
348
349
350
351
352
353 protected void setAnimationToggles(final OTSAnimationPanel animation)
354 {
355 AnimationToggles.setIconAnimationTogglesStandard(animation);
356 }
357
358
359
360
361
362
363
364
365
366
367 protected abstract OTSRoadNetwork setupSimulation(OTSSimulatorInterface sim) throws Exception;
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383 private class ScriptModel implements OTSModelInterface
384 {
385
386 private static final long serialVersionUID = 20180409L;
387
388
389
390
391 @SuppressWarnings("synthetic-access")
392 ScriptModel(final OTSSimulatorInterface simulator)
393 {
394 AbstractSimulationScript.this.simulator = simulator;
395 }
396
397
398 @SuppressWarnings("synthetic-access")
399 @Override
400 public void constructModel() throws SimRuntimeException
401 {
402 Map<String, StreamInterface> streams = new LinkedHashMap<>();
403 StreamInterface stream = new MersenneTwister(getSeed());
404 streams.put("generation", stream);
405 stream = new MersenneTwister(getSeed() + 1);
406 streams.put("default", stream);
407 AbstractSimulationScript.this.simulator.getModel().getStreams().putAll(streams);
408 AbstractSimulationScript.this.network =
409 Try.assign(() -> AbstractSimulationScript.this.setupSimulation(AbstractSimulationScript.this.simulator),
410 RuntimeException.class, "Exception while setting up simulation.");
411 try
412 {
413 AbstractSimulationScript.this.simulator.addListener(AbstractSimulationScript.this,
414 ReplicationInterface.END_REPLICATION_EVENT);
415 }
416 catch (RemoteException exception)
417 {
418 throw new SimRuntimeException(exception);
419 }
420 }
421
422
423 @SuppressWarnings("synthetic-access")
424 @Override
425 public OTSSimulatorInterface getSimulator()
426 {
427 return AbstractSimulationScript.this.simulator;
428 }
429
430
431 @SuppressWarnings("synthetic-access")
432 @Override
433 public OTSRoadNetwork getNetwork()
434 {
435 return AbstractSimulationScript.this.network;
436 }
437
438
439 @Override
440 public InputParameterMap getInputParameterMap()
441 {
442 return null;
443 }
444
445
446 @Override
447 public List<StatisticsInterface<Time, Duration, SimTimeDoubleUnit>> getOutputStatistics()
448 {
449 return null;
450 }
451
452
453 @SuppressWarnings("synthetic-access")
454 @Override
455 public String getShortName()
456 {
457 return AbstractSimulationScript.this.name;
458 }
459
460
461 @SuppressWarnings("synthetic-access")
462 @Override
463 public String getDescription()
464 {
465 return AbstractSimulationScript.this.description;
466 }
467
468
469 @Override
470 public void setStreamInformation(final StreamInformation streamInformation)
471 {
472
473 }
474
475
476 @Override
477 public StreamInformation getStreamInformation()
478 {
479
480 return null;
481 }
482
483 }
484
485 }