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 this.simulator = new OTSSimulator(this.name);
206 final ScriptModel scriptModel = new ScriptModel(this.simulator);
207 this.simulator.initialize(this.startTime, this.warmupTime, this.simulationTime, scriptModel);
208 this.simulator.addListener(this, Replication.END_REPLICATION_EVENT);
209 double tReport = 60.0;
210 Time t = this.simulator.getSimulatorTime();
211 while (t.si < this.simulationTime.si)
212 {
213 this.simulator.step();
214 t = this.simulator.getSimulatorTime();
215 if (t.si >= tReport)
216 {
217 System.out.println("Simulation time is " + t);
218 tReport += 60.0;
219 }
220 }
221
222 onSimulationEnd();
223 System.exit(0);
224 }
225 else
226 {
227 this.simulator = new OTSAnimator(this.name);
228 final ScriptModel scriptModel = new ScriptModel(this.simulator);
229 this.simulator.initialize(this.startTime, this.warmupTime, this.simulationTime, scriptModel);
230 OTSAnimationPanel animationPanel =
231 new OTSAnimationPanel(scriptModel.getNetwork().getExtent(), new Dimension(800, 600),
232 (OTSAnimator) this.simulator, scriptModel, getGtuColorer(), scriptModel.getNetwork());
233 setAnimationToggles(animationPanel);
234 animateNetwork(scriptModel.getNetwork());
235 setupDemo(animationPanel, scriptModel.getNetwork());
236 OTSSimulationApplication<ScriptModel> app = new OTSSimulationApplication<ScriptModel>(scriptModel, animationPanel)
237 {
238
239 private static final long serialVersionUID = 20190130L;
240
241
242 @Override
243 protected void animateNetwork() throws OTSDrawingException
244 {
245
246 }
247
248
249 @Override
250 protected void setAnimationToggles()
251 {
252
253 }
254 };
255 addTabs(this.simulator, app);
256 app.setExitOnClose(true);
257 }
258 }
259
260
261 @Override
262 public void notify(final EventInterface event) throws RemoteException
263 {
264 if (event.getType().equals(Replication.END_REPLICATION_EVENT))
265 {
266
267
268
269
270
271
272
273
274 onSimulationEnd();
275
276 AbstractSimulationScript.this.simulator.removeListener(AbstractSimulationScript.this,
277 Replication.END_REPLICATION_EVENT);
278 }
279 }
280
281
282
283
284
285 public final OTSSimulatorInterface getSimulator()
286 {
287 return AbstractSimulationScript.this.simulator;
288 }
289
290
291
292
293
294 public final OTSRoadNetwork getNetwork()
295 {
296 return AbstractSimulationScript.this.network;
297 }
298
299
300
301
302
303
304
305 protected void animateNetwork(final OTSNetwork net)
306 {
307 try
308 {
309 DefaultAnimationFactory.animateNetwork(net, net.getSimulator(), getGtuColorer());
310 }
311 catch (OTSDrawingException exception)
312 {
313 throw new RuntimeException("Exception while creating network animation.", exception);
314 }
315 }
316
317
318
319
320
321
322 protected void addTabs(final OTSSimulatorInterface sim, final OTSSimulationApplication<?> animation)
323 {
324
325 }
326
327
328
329
330 protected void onSimulationEnd()
331 {
332
333 }
334
335
336
337
338
339
340 protected void setupDemo(final OTSAnimationPanel animationPanel, final OTSRoadNetwork net)
341 {
342
343 }
344
345
346
347
348
349 protected void setAnimationToggles(final OTSAnimationPanel animation)
350 {
351 AnimationToggles.setIconAnimationTogglesStandard(animation);
352 }
353
354
355
356
357
358
359
360
361
362
363 protected abstract OTSRoadNetwork setupSimulation(OTSSimulatorInterface sim) throws Exception;
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379 private class ScriptModel implements OTSModelInterface
380 {
381
382 private static final long serialVersionUID = 20180409L;
383
384
385
386
387 @SuppressWarnings("synthetic-access")
388 ScriptModel(final OTSSimulatorInterface simulator)
389 {
390 AbstractSimulationScript.this.simulator = simulator;
391 }
392
393
394 @SuppressWarnings("synthetic-access")
395 @Override
396 public void constructModel() throws SimRuntimeException
397 {
398 Map<String, StreamInterface> streams = new LinkedHashMap<>();
399 StreamInterface stream = new MersenneTwister(getSeed());
400 streams.put("generation", stream);
401 stream = new MersenneTwister(getSeed() + 1);
402 streams.put("default", stream);
403 AbstractSimulationScript.this.simulator.getReplication().setStreams(streams);
404 AbstractSimulationScript.this.network =
405 Try.assign(() -> AbstractSimulationScript.this.setupSimulation(AbstractSimulationScript.this.simulator),
406 RuntimeException.class, "Exception while setting up simulation.");
407 try
408 {
409 AbstractSimulationScript.this.simulator.addListener(AbstractSimulationScript.this,
410 Replication.END_REPLICATION_EVENT);
411 }
412 catch (RemoteException exception)
413 {
414 throw new SimRuntimeException(exception);
415 }
416 }
417
418
419 @SuppressWarnings("synthetic-access")
420 @Override
421 public OTSSimulatorInterface getSimulator()
422 {
423 return AbstractSimulationScript.this.simulator;
424 }
425
426
427 @SuppressWarnings("synthetic-access")
428 @Override
429 public OTSRoadNetwork getNetwork()
430 {
431 return AbstractSimulationScript.this.network;
432 }
433
434
435 @Override
436 public InputParameterMap getInputParameterMap()
437 {
438 return null;
439 }
440
441
442 @Override
443 public List<OutputStatistic<?>> getOutputStatistics()
444 {
445 return null;
446 }
447
448
449 @SuppressWarnings("synthetic-access")
450 @Override
451 public String getShortName()
452 {
453 return AbstractSimulationScript.this.name;
454 }
455
456
457 @SuppressWarnings("synthetic-access")
458 @Override
459 public String getDescription()
460 {
461 return AbstractSimulationScript.this.description;
462 }
463 }
464
465 }