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