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.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.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.Network;
27 import org.opentrafficsim.draw.OtsDrawingException;
28 import org.opentrafficsim.road.network.RoadNetwork;
29 import org.opentrafficsim.swing.gui.AnimationToggles;
30 import org.opentrafficsim.swing.gui.OtsAnimationPanel;
31 import org.opentrafficsim.swing.gui.OtsSimulationApplication;
32 import org.opentrafficsim.swing.gui.OtsSwingApplication;
33
34 import nl.tudelft.simulation.dsol.SimRuntimeException;
35 import nl.tudelft.simulation.dsol.experiment.Replication;
36 import nl.tudelft.simulation.jstats.streams.MersenneTwister;
37 import nl.tudelft.simulation.jstats.streams.StreamInterface;
38 import picocli.CommandLine.Command;
39 import picocli.CommandLine.Option;
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 @Command(description = "Test program for CLI", name = "Program", mixinStandardHelpOptions = true, showDefaultValues = true)
55 public abstract class AbstractSimulationScript implements EventListener, Checkable
56 {
57
58 private static final long serialVersionUID = 20200129L;
59
60
61 private final String name;
62
63
64 private final String description;
65
66
67 private OtsSimulatorInterface simulator;
68
69
70 private RoadNetwork network;
71
72
73 private GtuColorer gtuColorer = OtsSwingApplication.DEFAULT_COLORER;
74
75
76 @Option(names = "--seed", description = "Seed", defaultValue = "1")
77 private long seed;
78
79
80 @Option(names = {"-s", "--startTime"}, description = "Start time", defaultValue = "0s")
81 private Time startTime;
82
83
84 @Option(names = {"-w", "--warmupTime"}, description = "Warm-up time", defaultValue = "0s")
85 private Duration warmupTime;
86
87
88 @Option(names = {"-t", "--simulationTime"}, description = "Simulation time (including warm-up time)",
89 defaultValue = "3600s")
90 private Duration simulationTime;
91
92
93 @Option(names = {"-a", "--autorun"}, description = "Autorun", negatable = true, defaultValue = "false")
94 private boolean autorun;
95
96
97
98
99
100
101 protected AbstractSimulationScript(final String name, final String description)
102 {
103 this.name = name;
104 this.description = description;
105 try
106 {
107 CliUtil.changeCommandName(this, this.name);
108 CliUtil.changeCommandDescription(this, this.description);
109 SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
110 CliUtil.changeCommandVersion(this,
111 formatter.format(new Date(ClassUtil.classFileDescriptor(this.getClass()).getLastChangedDate())));
112 }
113 catch (IllegalStateException | IllegalArgumentException | CliException exception)
114 {
115 throw new RuntimeException("Exception while setting properties in @Command annotation.", exception);
116 }
117 }
118
119
120
121
122
123 public long getSeed()
124 {
125 return this.seed;
126 }
127
128
129
130
131
132 public Time getStartTime()
133 {
134 return this.startTime;
135 }
136
137
138
139
140
141 public Duration getWarmupTime()
142 {
143 return this.warmupTime;
144 }
145
146
147
148
149
150 public Duration getSimulationTime()
151 {
152 return this.simulationTime;
153 }
154
155
156
157
158
159 public boolean isAutorun()
160 {
161 return this.autorun;
162 }
163
164
165
166
167
168 public final void setGtuColorer(final GtuColorer colorer)
169 {
170 this.gtuColorer = colorer;
171 }
172
173
174
175
176
177 public final GtuColorer getGtuColorer()
178 {
179 return this.gtuColorer;
180 }
181
182
183 @Override
184 public void check() throws Exception
185 {
186 Throw.when(this.seed < 0, IllegalArgumentException.class, "Seed should be positive");
187 Throw.when(this.warmupTime.si < 0.0, IllegalArgumentException.class, "Warm-up time should be positive");
188 Throw.when(this.simulationTime.si < 0.0, IllegalArgumentException.class, "Simulation time should be positive");
189 Throw.when(this.simulationTime.si < this.warmupTime.si, IllegalArgumentException.class,
190 "Simulation time should be longer than warm-up time");
191 }
192
193
194
195
196
197 public final void start() throws Exception
198 {
199 if (isAutorun())
200 {
201
202 this.simulator = new OtsSimulator(this.name);
203 final ScriptModel scriptModel = new ScriptModel(this.simulator);
204 this.simulator.initialize(this.startTime, this.warmupTime, this.simulationTime, scriptModel);
205 this.simulator.addListener(this, Replication.END_REPLICATION_EVENT);
206 double tReport = 60.0;
207 Time t = this.simulator.getSimulatorAbsTime();
208 while (t.si < this.simulationTime.si)
209 {
210 this.simulator.step();
211 t = this.simulator.getSimulatorAbsTime();
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(this.name);
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 setupDemo(animationPanel, scriptModel.getNetwork());
232 OtsSimulationApplication<ScriptModel> app = new OtsSimulationApplication<ScriptModel>(scriptModel, animationPanel)
233 {
234
235 private static final long serialVersionUID = 20190130L;
236
237
238 @Override
239 protected void setAnimationToggles()
240 {
241
242 }
243 };
244 addTabs(this.simulator, app);
245 app.setExitOnClose(true);
246 animationPanel.enableSimulationControlButtons();
247 }
248 }
249
250
251 @Override
252 public void notify(final Event event) throws RemoteException
253 {
254 if (event.getType().equals(Replication.END_REPLICATION_EVENT))
255 {
256
257
258
259
260
261
262
263
264 onSimulationEnd();
265
266 AbstractSimulationScript.this.simulator.removeListener(AbstractSimulationScript.this,
267 Replication.END_REPLICATION_EVENT);
268 }
269 }
270
271
272
273
274
275 public final OtsSimulatorInterface getSimulator()
276 {
277 return AbstractSimulationScript.this.simulator;
278 }
279
280
281
282
283
284 public final RoadNetwork getNetwork()
285 {
286 return AbstractSimulationScript.this.network;
287 }
288
289
290
291
292
293
294
295 protected void animateNetwork(final Network net)
296 {
297 try
298 {
299 DefaultAnimationFactory.animateNetwork(net, net.getSimulator(), getGtuColorer());
300 }
301 catch (OtsDrawingException exception)
302 {
303 throw new RuntimeException("Exception while creating network animation.", exception);
304 }
305 }
306
307
308
309
310
311
312 protected void addTabs(final OtsSimulatorInterface sim, final OtsSimulationApplication<?> animation)
313 {
314
315 }
316
317
318
319
320 protected void onSimulationEnd()
321 {
322
323 }
324
325
326
327
328
329
330 protected void setupDemo(final OtsAnimationPanel animationPanel, final RoadNetwork net)
331 {
332
333 }
334
335
336
337
338
339 protected void setAnimationToggles(final OtsAnimationPanel animation)
340 {
341 AnimationToggles.setIconAnimationTogglesStandard(animation);
342 }
343
344
345
346
347
348
349
350
351
352
353 protected abstract RoadNetwork setupSimulation(OtsSimulatorInterface sim) throws Exception;
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368 private class ScriptModel extends AbstractOtsModel
369 {
370
371 private static final long serialVersionUID = 20180409L;
372
373
374
375
376 @SuppressWarnings("synthetic-access")
377 ScriptModel(final OtsSimulatorInterface simulator)
378 {
379 super(simulator);
380 AbstractSimulationScript.this.simulator = simulator;
381 }
382
383
384 @SuppressWarnings("synthetic-access")
385 @Override
386 public void constructModel() throws SimRuntimeException
387 {
388 Map<String, StreamInterface> streams = new LinkedHashMap<>();
389 StreamInterface stream = new MersenneTwister(getSeed());
390 streams.put("generation", stream);
391 stream = new MersenneTwister(getSeed() + 1);
392 streams.put("default", stream);
393 AbstractSimulationScript.this.simulator.getModel().getStreams().putAll(streams);
394 AbstractSimulationScript.this.network =
395 Try.assign(() -> AbstractSimulationScript.this.setupSimulation(AbstractSimulationScript.this.simulator),
396 RuntimeException.class, "Exception while setting up simulation.");
397 try
398 {
399 AbstractSimulationScript.this.simulator.addListener(AbstractSimulationScript.this,
400 Replication.END_REPLICATION_EVENT);
401 }
402 catch (RemoteException exception)
403 {
404 throw new SimRuntimeException(exception);
405 }
406 }
407
408
409 @SuppressWarnings("synthetic-access")
410 @Override
411 public RoadNetwork getNetwork()
412 {
413 return AbstractSimulationScript.this.network;
414 }
415
416 }
417
418 }