1 package org.opentrafficsim.swing.script;
2
3 import java.awt.Dimension;
4 import java.io.Serializable;
5 import java.rmi.RemoteException;
6 import java.text.SimpleDateFormat;
7 import java.util.Date;
8 import java.util.LinkedHashMap;
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.AbstractOTSModel;
23 import org.opentrafficsim.core.dsol.OTSAnimator;
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.jstats.streams.MersenneTwister;
38 import nl.tudelft.simulation.jstats.streams.StreamInterface;
39 import picocli.CommandLine.Command;
40 import picocli.CommandLine.Option;
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 @Command(description = "Test program for CLI", name = "Program", mixinStandardHelpOptions = true, showDefaultValues = true)
57 public abstract class AbstractSimulationScript implements EventListenerInterface, Checkable
58 {
59
60 private static final long serialVersionUID = 20200129L;
61
62
63 private final String name;
64
65
66 private final String description;
67
68
69 private OTSSimulatorInterface simulator;
70
71
72 private OTSRoadNetwork network;
73
74
75 private GTUColorer gtuColorer = OTSSwingApplication.DEFAULT_COLORER;
76
77
78 @Option(names = "--seed", description = "Seed", defaultValue = "1")
79 private long seed;
80
81
82 @Option(names = { "-s", "--startTime" }, description = "Start time", defaultValue = "0s")
83 private Time startTime;
84
85
86 @Option(names = { "-w", "--warmupTime" }, description = "Warm-up time", defaultValue = "0s")
87 private Duration warmupTime;
88
89
90 @Option(names = { "-t", "--simulationTime" }, description = "Simulation time (including warm-up time)",
91 defaultValue = "3600s")
92 private Duration simulationTime;
93
94
95 @Option(names = { "-a", "--autorun" }, description = "Autorun", negatable = true, defaultValue = "false")
96 private boolean autorun;
97
98
99
100
101
102
103 protected AbstractSimulationScript(final String name, final String description)
104 {
105 this.name = name;
106 this.description = description;
107 try
108 {
109 CliUtil.changeCommandName(this, this.name);
110 CliUtil.changeCommandDescription(this, this.description);
111 SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
112 CliUtil.changeCommandVersion(this,
113 formatter.format(new Date(ClassUtil.classFileDescriptor(this.getClass()).getLastChangedDate())));
114 }
115 catch (IllegalStateException | IllegalArgumentException | CliException exception)
116 {
117 throw new RuntimeException("Exception while setting properties in @Command annotation.", exception);
118 }
119 }
120
121
122
123
124
125 public long getSeed()
126 {
127 return this.seed;
128 }
129
130
131
132
133
134 public Time getStartTime()
135 {
136 return this.startTime;
137 }
138
139
140
141
142
143 public Duration getWarmupTime()
144 {
145 return this.warmupTime;
146 }
147
148
149
150
151
152 public Duration getSimulationTime()
153 {
154 return this.simulationTime;
155 }
156
157
158
159
160
161 public boolean isAutorun()
162 {
163 return this.autorun;
164 }
165
166
167
168
169
170 public final void setGtuColorer(final GTUColorer colorer)
171 {
172 this.gtuColorer = colorer;
173 }
174
175
176
177
178
179 public final GTUColorer getGtuColorer()
180 {
181 return this.gtuColorer;
182 }
183
184
185 @Override
186 public void check() throws Exception
187 {
188 Throw.when(this.seed < 0, IllegalArgumentException.class, "Seed should be positive");
189 Throw.when(this.warmupTime.si < 0.0, IllegalArgumentException.class, "Warm-up time should be positive");
190 Throw.when(this.simulationTime.si < 0.0, IllegalArgumentException.class, "Simulation time should be positive");
191 Throw.when(this.simulationTime.si < this.warmupTime.si, IllegalArgumentException.class,
192 "Simulation time should be longer than warmp-up time");
193 }
194
195
196
197
198
199 public final void start() throws Exception
200 {
201 if (isAutorun())
202 {
203
204 this.simulator = new OTSSimulator(this.name);
205 final ScriptModel scriptModel = new ScriptModel(this.simulator);
206 this.simulator.initialize(this.startTime, this.warmupTime, this.simulationTime, scriptModel);
207 this.simulator.addListener(this, ReplicationInterface.END_REPLICATION_EVENT);
208 double tReport = 60.0;
209 Time t = this.simulator.getSimulatorAbsTime();
210 while (t.si < this.simulationTime.si)
211 {
212 this.simulator.step();
213 t = this.simulator.getSimulatorAbsTime();
214 if (t.si >= tReport)
215 {
216 System.out.println("Simulation time is " + t);
217 tReport += 60.0;
218 }
219 }
220
221 onSimulationEnd();
222 System.exit(0);
223 }
224 else
225 {
226 this.simulator = new OTSAnimator(this.name);
227 final ScriptModel scriptModel = new ScriptModel(this.simulator);
228 this.simulator.initialize(this.startTime, this.warmupTime, this.simulationTime, scriptModel);
229 OTSAnimationPanel animationPanel =
230 new OTSAnimationPanel(scriptModel.getNetwork().getExtent(), new Dimension(800, 600),
231 (OTSAnimator) this.simulator, scriptModel, getGtuColorer(), scriptModel.getNetwork());
232 setAnimationToggles(animationPanel);
233 animateNetwork(scriptModel.getNetwork());
234 setupDemo(animationPanel, scriptModel.getNetwork());
235 OTSSimulationApplication<ScriptModel> app = new OTSSimulationApplication<ScriptModel>(scriptModel, animationPanel)
236 {
237
238 private static final long serialVersionUID = 20190130L;
239
240
241 @Override
242 protected void animateNetwork() throws OTSDrawingException
243 {
244
245 }
246
247
248 @Override
249 protected void setAnimationToggles()
250 {
251
252 }
253 };
254 addTabs(this.simulator, app);
255 app.setExitOnClose(true);
256 animationPanel.enableSimulationControlButtons();
257 }
258 }
259
260
261 @Override
262 public void notify(final EventInterface event) throws RemoteException
263 {
264 if (event.getType().equals(ReplicationInterface.END_REPLICATION_EVENT))
265 {
266
267
268
269
270
271
272
273
274 onSimulationEnd();
275
276 AbstractSimulationScript.this.simulator.removeListener(AbstractSimulationScript.this,
277 ReplicationInterface.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 extends AbstractOTSModel
380 {
381
382 private static final long serialVersionUID = 20180409L;
383
384
385
386
387 @SuppressWarnings("synthetic-access")
388 ScriptModel(final OTSSimulatorInterface simulator)
389 {
390 super(simulator);
391 AbstractSimulationScript.this.simulator = simulator;
392 }
393
394
395 @SuppressWarnings("synthetic-access")
396 @Override
397 public void constructModel() throws SimRuntimeException
398 {
399 Map<String, StreamInterface> streams = new LinkedHashMap<>();
400 StreamInterface stream = new MersenneTwister(getSeed());
401 streams.put("generation", stream);
402 stream = new MersenneTwister(getSeed() + 1);
403 streams.put("default", stream);
404 AbstractSimulationScript.this.simulator.getModel().getStreams().putAll(streams);
405 AbstractSimulationScript.this.network =
406 Try.assign(() -> AbstractSimulationScript.this.setupSimulation(AbstractSimulationScript.this.simulator),
407 RuntimeException.class, "Exception while setting up simulation.");
408 try
409 {
410 AbstractSimulationScript.this.simulator.addListener(AbstractSimulationScript.this,
411 ReplicationInterface.END_REPLICATION_EVENT);
412 }
413 catch (RemoteException exception)
414 {
415 throw new SimRuntimeException(exception);
416 }
417 }
418
419
420 @SuppressWarnings("synthetic-access")
421 @Override
422 public OTSRoadNetwork getNetwork()
423 {
424 return AbstractSimulationScript.this.network;
425 }
426
427
428 @Override
429 public Serializable getSourceId()
430 {
431 return getShortName();
432 }
433
434 }
435
436 }