1 package org.opentrafficsim.swing.script;
2
3 import java.text.SimpleDateFormat;
4 import java.util.Collections;
5 import java.util.Date;
6 import java.util.LinkedHashMap;
7 import java.util.List;
8 import java.util.Map;
9
10 import org.djunits.value.vdouble.scalar.Duration;
11 import org.djunits.value.vdouble.scalar.Time;
12 import org.djutils.cli.Checkable;
13 import org.djutils.cli.CliException;
14 import org.djutils.cli.CliUtil;
15 import org.djutils.event.Event;
16 import org.djutils.event.EventListener;
17 import org.djutils.exceptions.Throw;
18 import org.djutils.exceptions.Try;
19 import org.djutils.reflection.ClassUtil;
20 import org.opentrafficsim.animation.DefaultAnimationFactory;
21 import org.opentrafficsim.base.OtsRuntimeException;
22 import org.opentrafficsim.base.logger.Logger;
23 import org.opentrafficsim.core.dsol.AbstractOtsModel;
24 import org.opentrafficsim.core.dsol.OtsAnimator;
25 import org.opentrafficsim.core.dsol.OtsSimulator;
26 import org.opentrafficsim.core.dsol.OtsSimulatorInterface;
27 import org.opentrafficsim.core.gtu.Gtu;
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.colorer.Colorer;
32 import org.opentrafficsim.draw.gtu.DefaultCarAnimation.GtuData.GtuMarker;
33 import org.opentrafficsim.road.network.RoadNetwork;
34 import org.opentrafficsim.swing.gui.AnimationToggles;
35 import org.opentrafficsim.swing.gui.OtsAnimationPanel;
36 import org.opentrafficsim.swing.gui.OtsSimulationApplication;
37 import org.opentrafficsim.swing.gui.OtsSwingApplication;
38
39 import nl.tudelft.simulation.dsol.SimRuntimeException;
40 import nl.tudelft.simulation.dsol.experiment.Replication;
41 import nl.tudelft.simulation.jstats.streams.MersenneTwister;
42 import nl.tudelft.simulation.jstats.streams.StreamInterface;
43 import picocli.CommandLine.Command;
44 import picocli.CommandLine.Option;
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 @Command(description = "Test program for CLI", name = "Program", mixinStandardHelpOptions = true, showDefaultValues = true)
60 public abstract class AbstractSimulationScript implements EventListener, Checkable
61 {
62
63 private final String name;
64
65
66 private final String description;
67
68
69 private OtsSimulatorInterface simulator;
70
71
72 private RoadNetwork network;
73
74
75 private List<Colorer<? super Gtu>> gtuColorers = OtsSwingApplication.DEFAULT_GTU_COLORERS;
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 = {"-h", "--history"}, description = "Guaranteed history time", defaultValue = "0s")
96 private Duration historyTime;
97
98
99 @Option(names = {"-a", "--autorun"}, description = "Autorun", negatable = true, defaultValue = "false")
100 private boolean autorun;
101
102
103
104
105
106
107 protected AbstractSimulationScript(final String name, final String description)
108 {
109 this.name = name;
110 this.description = description;
111 try
112 {
113 CliUtil.changeCommandName(this, this.name);
114 CliUtil.changeCommandDescription(this, this.description);
115 SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
116 CliUtil.changeCommandVersion(this,
117 formatter.format(new Date(ClassUtil.classFileDescriptorForClass(this.getClass()).getLastChangedDate())));
118 }
119 catch (IllegalStateException | IllegalArgumentException | CliException exception)
120 {
121 throw new OtsRuntimeException("Exception while setting properties in @Command annotation.", exception);
122 }
123 }
124
125
126
127
128
129 public long getSeed()
130 {
131 return this.seed;
132 }
133
134
135
136
137
138 public Time getStartTime()
139 {
140 return this.startTime;
141 }
142
143
144
145
146
147 public Duration getWarmupTime()
148 {
149 return this.warmupTime;
150 }
151
152
153
154
155
156 public Duration getSimulationTime()
157 {
158 return this.simulationTime;
159 }
160
161
162
163
164
165 public boolean isAutorun()
166 {
167 return this.autorun;
168 }
169
170
171
172
173
174 public final void setGtuColorers(final List<Colorer<? super Gtu>> colorers)
175 {
176 this.gtuColorers = colorers;
177 }
178
179
180
181
182
183 public final List<Colorer<? super Gtu>> getGtuColorers()
184 {
185 return this.gtuColorers;
186 }
187
188
189
190
191
192 public Map<GtuType, GtuMarker> getGtuMarkers()
193 {
194 return Collections.emptyMap();
195 }
196
197 @Override
198 public void check() throws Exception
199 {
200 Throw.when(this.seed < 0, IllegalArgumentException.class, "Seed should be positive");
201 Throw.when(this.warmupTime.si < 0.0, IllegalArgumentException.class, "Warm-up time should be positive");
202 Throw.when(this.simulationTime.si < 0.0, IllegalArgumentException.class, "Simulation time should be positive");
203 Throw.when(this.simulationTime.si < this.warmupTime.si, IllegalArgumentException.class,
204 "Simulation time should be longer than warm-up time");
205 }
206
207
208
209
210
211 public final void start() throws Exception
212 {
213 if (isAutorun())
214 {
215
216 this.simulator = new OtsSimulator(this.name);
217 final ScriptModel scriptModel = new ScriptModel(this.simulator);
218 this.simulator.initialize(this.startTime, this.warmupTime, this.simulationTime, scriptModel,
219 new HistoryManagerDevs(this.simulator, this.historyTime, Duration.ofSI(10.0)));
220 this.simulator.addListener(this, Replication.END_REPLICATION_EVENT);
221 double tReport = 60.0;
222 Duration t = this.simulator.getSimulatorTime();
223 while (t.si < this.simulationTime.si)
224 {
225 this.simulator.step();
226 t = this.simulator.getSimulatorTime();
227 if (t.si >= tReport)
228 {
229 Logger.ots().info("Simulation time is " + t);
230 tReport += 60.0;
231 }
232 }
233
234 onSimulationEnd();
235 System.exit(0);
236 }
237 else
238 {
239 this.simulator = new OtsAnimator(this.name);
240 final ScriptModel scriptModel = new ScriptModel(this.simulator);
241 this.simulator.initialize(this.startTime, this.warmupTime, this.simulationTime, scriptModel,
242 new HistoryManagerDevs(this.simulator, this.historyTime, Duration.ofSI(10.0)));
243 OtsAnimationPanel animationPanel = new OtsAnimationPanel(scriptModel.getNetwork().getExtent(),
244 (OtsAnimator) this.simulator, scriptModel, getGtuColorers(), scriptModel.getNetwork());
245 setAnimationToggles(animationPanel);
246 setupDemo(animationPanel, scriptModel.getNetwork());
247 OtsSimulationApplication<ScriptModel> app =
248 new OtsSimulationApplication<ScriptModel>(scriptModel, animationPanel, getGtuMarkers())
249 {
250
251 private static final long serialVersionUID = 20190130L;
252
253 @Override
254 protected void setAnimationToggles()
255 {
256
257 }
258 };
259 addTabs(this.simulator, app);
260 app.setExitOnClose(true);
261 animationPanel.enableSimulationControlButtons();
262 }
263 }
264
265 @Override
266 public void notify(final Event event)
267 {
268 if (event.getType().equals(Replication.END_REPLICATION_EVENT))
269 {
270
271
272
273
274
275
276
277
278 onSimulationEnd();
279
280 AbstractSimulationScript.this.simulator.removeListener(AbstractSimulationScript.this,
281 Replication.END_REPLICATION_EVENT);
282 }
283 }
284
285
286
287
288
289 public final OtsSimulatorInterface getSimulator()
290 {
291 return AbstractSimulationScript.this.simulator;
292 }
293
294
295
296
297
298 public final RoadNetwork getNetwork()
299 {
300 return AbstractSimulationScript.this.network;
301 }
302
303
304
305
306
307
308
309
310 protected void animateNetwork(final Network net, final OtsAnimationPanel animationPanel)
311 {
312 DefaultAnimationFactory.animateNetwork(net, net.getSimulator(),
313 animationPanel.getColorControlPanel().getGtuColorerManager(), getGtuMarkers());
314 }
315
316
317
318
319
320
321 protected void addTabs(final OtsSimulatorInterface sim, final OtsSimulationApplication<?> animation)
322 {
323
324 }
325
326
327
328
329 protected void onSimulationEnd()
330 {
331
332 }
333
334
335
336
337
338
339 protected void setupDemo(final OtsAnimationPanel animationPanel, final RoadNetwork net)
340 {
341
342 }
343
344
345
346
347
348 protected void setAnimationToggles(final OtsAnimationPanel animation)
349 {
350 AnimationToggles.setIconAnimationTogglesStandard(animation);
351 }
352
353
354
355
356
357
358
359
360
361
362 protected abstract RoadNetwork setupSimulation(OtsSimulatorInterface sim) throws Exception;
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377 private class ScriptModel extends AbstractOtsModel
378 {
379
380
381
382 @SuppressWarnings("synthetic-access")
383 ScriptModel(final OtsSimulatorInterface simulator)
384 {
385 super(simulator);
386 AbstractSimulationScript.this.simulator = simulator;
387 }
388
389 @SuppressWarnings("synthetic-access")
390 @Override
391 public void constructModel() throws SimRuntimeException
392 {
393 Map<String, StreamInterface> streams = new LinkedHashMap<>();
394 StreamInterface stream = new MersenneTwister(getSeed());
395 streams.put("generation", stream);
396 stream = new MersenneTwister(getSeed() + 1);
397 streams.put("default", stream);
398 AbstractSimulationScript.this.simulator.getModel().getStreams().putAll(streams);
399 AbstractSimulationScript.this.network =
400 Try.assign(() -> AbstractSimulationScript.this.setupSimulation(AbstractSimulationScript.this.simulator),
401 OtsRuntimeException.class, "Exception while setting up simulation.");
402 AbstractSimulationScript.this.simulator.addListener(AbstractSimulationScript.this,
403 Replication.END_REPLICATION_EVENT);
404 }
405
406 @SuppressWarnings("synthetic-access")
407 @Override
408 public RoadNetwork getNetwork()
409 {
410 return AbstractSimulationScript.this.network;
411 }
412
413 }
414
415 }