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