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.Collections;
7 import java.util.Date;
8 import java.util.LinkedHashMap;
9 import java.util.List;
10 import java.util.Map;
11
12 import org.djunits.value.vdouble.scalar.Duration;
13 import org.djunits.value.vdouble.scalar.Time;
14 import org.djutils.cli.Checkable;
15 import org.djutils.cli.CliException;
16 import org.djutils.cli.CliUtil;
17 import org.djutils.event.Event;
18 import org.djutils.event.EventListener;
19 import org.djutils.exceptions.Throw;
20 import org.djutils.exceptions.Try;
21 import org.djutils.reflection.ClassUtil;
22 import org.opentrafficsim.animation.DefaultAnimationFactory;
23 import org.opentrafficsim.animation.gtu.colorer.GtuColorer;
24 import org.opentrafficsim.core.dsol.AbstractOtsModel;
25 import org.opentrafficsim.core.dsol.OtsAnimator;
26 import org.opentrafficsim.core.dsol.OtsSimulator;
27 import org.opentrafficsim.core.dsol.OtsSimulatorInterface;
28 import org.opentrafficsim.core.gtu.GtuType;
29 import org.opentrafficsim.core.network.Network;
30 import org.opentrafficsim.core.perception.HistoryManagerDevs;
31 import org.opentrafficsim.draw.gtu.DefaultCarAnimation.GtuData.GtuMarker;
32 import org.opentrafficsim.road.network.RoadNetwork;
33 import org.opentrafficsim.swing.gui.AnimationToggles;
34 import org.opentrafficsim.swing.gui.OtsAnimationPanel;
35 import org.opentrafficsim.swing.gui.OtsSimulationApplication;
36 import org.opentrafficsim.swing.gui.OtsSwingApplication;
37
38 import nl.tudelft.simulation.dsol.SimRuntimeException;
39 import nl.tudelft.simulation.dsol.experiment.Replication;
40 import nl.tudelft.simulation.jstats.streams.MersenneTwister;
41 import nl.tudelft.simulation.jstats.streams.StreamInterface;
42 import picocli.CommandLine.Command;
43 import picocli.CommandLine.Option;
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 EventListener, 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 RoadNetwork network;
75
76
77 private List<GtuColorer> gtuColorers = OtsSwingApplication.DEFAULT_GTU_COLORERS;
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 = {"-h", "--history"}, description = "Guaranteed history time", defaultValue = "0s")
98 private Duration historyTime;
99
100
101 @Option(names = {"-a", "--autorun"}, description = "Autorun", negatable = true, defaultValue = "false")
102 private boolean autorun;
103
104
105
106
107
108
109 protected AbstractSimulationScript(final String name, final String description)
110 {
111 this.name = name;
112 this.description = description;
113 try
114 {
115 CliUtil.changeCommandName(this, this.name);
116 CliUtil.changeCommandDescription(this, this.description);
117 SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
118 CliUtil.changeCommandVersion(this,
119 formatter.format(new Date(ClassUtil.classFileDescriptor(this.getClass()).getLastChangedDate())));
120 }
121 catch (IllegalStateException | IllegalArgumentException | CliException exception)
122 {
123 throw new RuntimeException("Exception while setting properties in @Command annotation.", exception);
124 }
125 }
126
127
128
129
130
131 public long getSeed()
132 {
133 return this.seed;
134 }
135
136
137
138
139
140 public Time getStartTime()
141 {
142 return this.startTime;
143 }
144
145
146
147
148
149 public Duration getWarmupTime()
150 {
151 return this.warmupTime;
152 }
153
154
155
156
157
158 public Duration getSimulationTime()
159 {
160 return this.simulationTime;
161 }
162
163
164
165
166
167 public boolean isAutorun()
168 {
169 return this.autorun;
170 }
171
172
173
174
175
176 public final void setGtuColorers(final List<GtuColorer> colorers)
177 {
178 this.gtuColorers = colorers;
179 }
180
181
182
183
184
185 public final List<GtuColorer> getGtuColorers()
186 {
187 return this.gtuColorers;
188 }
189
190
191
192
193
194 public Map<GtuType, GtuMarker> getGtuMarkers()
195 {
196 return Collections.emptyMap();
197 }
198
199 @Override
200 public void check() throws Exception
201 {
202 Throw.when(this.seed < 0, IllegalArgumentException.class, "Seed should be positive");
203 Throw.when(this.warmupTime.si < 0.0, IllegalArgumentException.class, "Warm-up time should be positive");
204 Throw.when(this.simulationTime.si < 0.0, IllegalArgumentException.class, "Simulation time should be positive");
205 Throw.when(this.simulationTime.si < this.warmupTime.si, IllegalArgumentException.class,
206 "Simulation time should be longer than warm-up time");
207 }
208
209
210
211
212
213 public final void start() throws Exception
214 {
215 if (isAutorun())
216 {
217
218 this.simulator = new OtsSimulator(this.name);
219 final ScriptModel scriptModel = new ScriptModel(this.simulator);
220 this.simulator.initialize(this.startTime, this.warmupTime, this.simulationTime, scriptModel,
221 new HistoryManagerDevs(this.simulator, this.historyTime, Duration.instantiateSI(10.0)));
222 this.simulator.addListener(this, Replication.END_REPLICATION_EVENT);
223 double tReport = 60.0;
224 Time t = this.simulator.getSimulatorAbsTime();
225 while (t.si < this.simulationTime.si)
226 {
227 this.simulator.step();
228 t = this.simulator.getSimulatorAbsTime();
229 if (t.si >= tReport)
230 {
231 System.out.println("Simulation time is " + t);
232 tReport += 60.0;
233 }
234 }
235
236 onSimulationEnd();
237 System.exit(0);
238 }
239 else
240 {
241 this.simulator = new OtsAnimator(this.name);
242 final ScriptModel scriptModel = new ScriptModel(this.simulator);
243 this.simulator.initialize(this.startTime, this.warmupTime, this.simulationTime, scriptModel,
244 new HistoryManagerDevs(this.simulator, this.historyTime, Duration.instantiateSI(10.0)));
245 OtsAnimationPanel animationPanel =
246 new OtsAnimationPanel(scriptModel.getNetwork().getExtent(), new Dimension(800, 600),
247 (OtsAnimator) this.simulator, scriptModel, getGtuColorers(), scriptModel.getNetwork());
248 setAnimationToggles(animationPanel);
249 setupDemo(animationPanel, scriptModel.getNetwork());
250 OtsSimulationApplication<ScriptModel> app =
251 new OtsSimulationApplication<ScriptModel>(scriptModel, animationPanel, getGtuMarkers())
252 {
253
254 private static final long serialVersionUID = 20190130L;
255
256 @Override
257 protected void setAnimationToggles()
258 {
259
260 }
261 };
262 addTabs(this.simulator, app);
263 app.setExitOnClose(true);
264 animationPanel.enableSimulationControlButtons();
265 }
266 }
267
268 @Override
269 public void notify(final Event event) throws RemoteException
270 {
271 if (event.getType().equals(Replication.END_REPLICATION_EVENT))
272 {
273
274
275
276
277
278
279
280
281 onSimulationEnd();
282
283 AbstractSimulationScript.this.simulator.removeListener(AbstractSimulationScript.this,
284 Replication.END_REPLICATION_EVENT);
285 }
286 }
287
288
289
290
291
292 public final OtsSimulatorInterface getSimulator()
293 {
294 return AbstractSimulationScript.this.simulator;
295 }
296
297
298
299
300
301 public final RoadNetwork getNetwork()
302 {
303 return AbstractSimulationScript.this.network;
304 }
305
306
307
308
309
310
311
312
313 protected void animateNetwork(final Network net, final OtsAnimationPanel animationPanel)
314 {
315 DefaultAnimationFactory.animateNetwork(net, net.getSimulator(),
316 animationPanel.getColorControlPanel().getGtuColorerManager(), getGtuMarkers());
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 RoadNetwork 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 RoadNetwork setupSimulation(OtsSimulatorInterface sim) throws Exception;
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380 private class ScriptModel extends AbstractOtsModel
381 {
382
383 private static final long serialVersionUID = 20180409L;
384
385
386
387
388 @SuppressWarnings("synthetic-access")
389 ScriptModel(final OtsSimulatorInterface simulator)
390 {
391 super(simulator);
392 AbstractSimulationScript.this.simulator = simulator;
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 Replication.END_REPLICATION_EVENT);
412 }
413 catch (RemoteException exception)
414 {
415 throw new SimRuntimeException(exception);
416 }
417 }
418
419 @SuppressWarnings("synthetic-access")
420 @Override
421 public RoadNetwork getNetwork()
422 {
423 return AbstractSimulationScript.this.network;
424 }
425
426 }
427
428 }