1 package org.opentrafficsim.demo;
2
3 import java.io.IOException;
4 import java.io.Serializable;
5 import java.util.ArrayList;
6 import java.util.LinkedHashSet;
7 import java.util.List;
8 import java.util.Random;
9 import java.util.Set;
10
11 import org.djunits.unit.DirectionUnit;
12 import org.djunits.unit.DurationUnit;
13 import org.djunits.unit.LengthUnit;
14 import org.djunits.unit.util.UNITS;
15 import org.djunits.value.vdouble.scalar.Acceleration;
16 import org.djunits.value.vdouble.scalar.Direction;
17 import org.djunits.value.vdouble.scalar.Duration;
18 import org.djunits.value.vdouble.scalar.Length;
19 import org.djunits.value.vdouble.scalar.Speed;
20 import org.djutils.traceverifier.TraceVerifier;
21 import org.opentrafficsim.base.parameters.Parameters;
22 import org.opentrafficsim.core.dsol.AbstractOTSModel;
23 import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
24 import org.opentrafficsim.core.geometry.OTSGeometryException;
25 import org.opentrafficsim.core.geometry.OTSPoint3D;
26 import org.opentrafficsim.core.gtu.GTU;
27 import org.opentrafficsim.core.gtu.GTUDirectionality;
28 import org.opentrafficsim.core.gtu.GTUException;
29 import org.opentrafficsim.core.gtu.GTUType;
30 import org.opentrafficsim.core.network.NetworkException;
31 import org.opentrafficsim.core.network.route.Route;
32 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
33 import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
34 import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusFactory;
35 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.DefaultLMRSPerceptionFactory;
36 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.LMRSFactory;
37 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
38 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlannerFactory;
39 import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlannerFactory;
40 import org.opentrafficsim.road.network.OTSRoadNetwork;
41 import org.opentrafficsim.road.network.factory.LaneFactory;
42 import org.opentrafficsim.road.network.lane.DirectedLanePosition;
43 import org.opentrafficsim.road.network.lane.Lane;
44 import org.opentrafficsim.road.network.lane.LaneType;
45 import org.opentrafficsim.road.network.lane.OTSRoadNode;
46
47 import nl.tudelft.simulation.dsol.SimRuntimeException;
48 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterBoolean;
49 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterDouble;
50 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterDoubleScalar;
51 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterException;
52 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterMap;
53 import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
54 import nl.tudelft.simulation.jstats.streams.MersenneTwister;
55 import nl.tudelft.simulation.jstats.streams.StreamInterface;
56
57
58
59
60
61
62
63
64
65
66
67 public class CircularRoadModel extends AbstractOTSModel implements UNITS
68 {
69
70 private static final long serialVersionUID = 20141121L;
71
72
73 private int carsCreated = 0;
74
75
76 private double carProbability;
77
78
79 private Length minimumDistance = new Length(0, METER);
80
81
82 private Speed speedLimit = new Speed(100, KM_PER_HOUR);
83
84
85 private List<List<Lane>> paths = new ArrayList<>();
86
87
88 private StreamInterface stream = new MersenneTwister(12345);
89
90
91 private LaneBasedStrategicalPlannerFactory<LaneBasedStrategicalPlanner> strategicalPlannerGeneratorCars = null;
92
93
94 private LaneBasedStrategicalPlannerFactory<LaneBasedStrategicalPlanner> strategicalPlannerGeneratorTrucks = null;
95
96
97 private Parameters parametersCar;
98
99
100 private Parameters parametersTruck;
101
102
103 private final OTSRoadNetwork network;
104
105
106
107
108 public CircularRoadModel(final OTSSimulatorInterface simulator)
109 {
110 super(simulator);
111 this.network = new OTSRoadNetwork("network", true, simulator);
112 makeInputParameterMap();
113 }
114
115
116
117
118 public void makeInputParameterMap()
119 {
120 try
121 {
122 InputParameterHelper.makeInputParameterMapCarTruck(this.inputParameterMap, 1.0);
123
124 InputParameterMap genericMap = null;
125 if (this.inputParameterMap.getValue().containsKey("generic"))
126 {
127 genericMap = (InputParameterMap) this.inputParameterMap.get("generic");
128 }
129 else
130 {
131 genericMap = new InputParameterMap("generic", "Generic", "Generic parameters", 1.0);
132 this.inputParameterMap.add(genericMap);
133 }
134
135 genericMap.add(new InputParameterDoubleScalar<LengthUnit, Length>("trackLength", "Track length",
136 "Track length (circumfence of the track)", Length.instantiateSI(1000.0), Length.instantiateSI(500.0),
137 Length.instantiateSI(2000.0), true, true, "%.0f", 1.5));
138 genericMap.add(new InputParameterDouble("densityMean", "Mean density (veh / km)",
139 "mean density of the vehicles (vehicles per kilometer)", 30.0, 5.0, 45.0, true, true, "%.0f", 2.0));
140 genericMap.add(new InputParameterDouble("densityVariability", "Density variability",
141 "Variability of the denisty: variability * (headway - 20) meters", 0.0, 0.0, 1.0, true, true, "%.00f",
142 3.0));
143 genericMap.add(new InputParameterBoolean("gradualLaneChange", "Gradual lane change",
144 "Gradual lane change when true; instantaneous lane change when false", true, 4.0));
145 }
146 catch (InputParameterException exception)
147 {
148 exception.printStackTrace();
149 }
150 }
151
152
153
154
155
156 public List<Lane> getPath(final int index)
157 {
158 return this.paths.get(index);
159 }
160
161
162
163
164
165 public void sample(final TraceVerifier tv)
166 {
167 try
168 {
169 StringBuilder state = new StringBuilder();
170 for (GTU gtu : this.network.getGTUs())
171 {
172 LaneBasedGTU lbg = (LaneBasedGTU) gtu;
173 state.append(String.format("%s: %130.130s ", lbg.getId(), lbg.getLocation().toString()));
174 }
175
176 tv.sample(this.simulator.getSimulatorTime().toString(), state.toString());
177 this.simulator.scheduleEventRel(new Duration(1, DurationUnit.SECOND), this, this, "sample", new Object[] { tv });
178 }
179 catch (IOException e)
180 {
181 e.printStackTrace();
182 }
183 }
184
185
186 @Override
187 public void constructModel() throws SimRuntimeException
188 {
189 try
190 {
191
192
193
194
195
196 final int laneCount = 2;
197 for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
198 {
199 this.paths.add(new ArrayList<Lane>());
200 }
201
202 this.carProbability = (double) getInputParameter("generic.carProbability");
203 double radius = ((Length) getInputParameter("generic.trackLength")).si / 2 / Math.PI;
204 double headway = 1000.0 / (double) getInputParameter("generic.densityMean");
205 double headwayVariability = (double) getInputParameter("generic.densityVariability");
206
207 this.parametersCar = InputParameterHelper.getParametersCar(getInputParameterMap());
208 this.parametersTruck = InputParameterHelper.getParametersTruck(getInputParameterMap());
209
210 this.strategicalPlannerGeneratorCars = new LaneBasedStrategicalRoutePlannerFactory(
211 new LMRSFactory(new IDMPlusFactory(this.stream), new DefaultLMRSPerceptionFactory()));
212 this.strategicalPlannerGeneratorTrucks = new LaneBasedStrategicalRoutePlannerFactory(
213 new LMRSFactory(new IDMPlusFactory(this.stream), new DefaultLMRSPerceptionFactory()));
214
215 GTUType gtuType = this.network.getGtuType(GTUType.DEFAULTS.CAR);
216 LaneType laneType = this.network.getLaneType(LaneType.DEFAULTS.TWO_WAY_LANE);
217 OTSRoadNode start = new OTSRoadNode(this.network, "Start", new OTSPoint3D(radius, 0, 0),
218 new Direction(90, DirectionUnit.EAST_DEGREE));
219 OTSRoadNode halfway = new OTSRoadNode(this.network, "Halfway", new OTSPoint3D(-radius, 0, 0),
220 new Direction(270, DirectionUnit.EAST_DEGREE));
221
222 OTSPoint3D[] coordsHalf1 = new OTSPoint3D[127];
223 for (int i = 0; i < coordsHalf1.length; i++)
224 {
225 double angle = Math.PI * (1 + i) / (1 + coordsHalf1.length);
226 coordsHalf1[i] = new OTSPoint3D(radius * Math.cos(angle), radius * Math.sin(angle), 0);
227 }
228 Lane[] lanes1 = LaneFactory.makeMultiLane(this.network, "FirstHalf", start, halfway, coordsHalf1, laneCount,
229 laneType, this.speedLimit, this.simulator);
230 OTSPoint3D[] coordsHalf2 = new OTSPoint3D[127];
231 for (int i = 0; i < coordsHalf2.length; i++)
232 {
233 double angle = Math.PI + Math.PI * (1 + i) / (1 + coordsHalf2.length);
234 coordsHalf2[i] = new OTSPoint3D(radius * Math.cos(angle), radius * Math.sin(angle), 0);
235 }
236 Lane[] lanes2 = LaneFactory.makeMultiLane(this.network, "SecondHalf", halfway, start, coordsHalf2, laneCount,
237 laneType, this.speedLimit, this.simulator);
238 for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
239 {
240 this.paths.get(laneIndex).add(lanes1[laneIndex]);
241 this.paths.get(laneIndex).add(lanes2[laneIndex]);
242 }
243
244 double variability = (headway - 20) * headwayVariability;
245 System.out.println("headway is " + headway + " variability limit is " + variability);
246 Random random = new Random(12345);
247 for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
248 {
249 double lane1Length = lanes1[laneIndex].getLength().getSI();
250 double trackLength = lane1Length + lanes2[laneIndex].getLength().getSI();
251 for (double pos = 0; pos <= trackLength - headway - variability;)
252 {
253 Lane lane = pos >= lane1Length ? lanes2[laneIndex] : lanes1[laneIndex];
254
255 double laneRelativePos = pos > lane1Length ? pos - lane1Length : pos;
256 double actualHeadway = headway + (random.nextDouble() * 2 - 1) * variability;
257
258 generateGTU(new Length(laneRelativePos, METER), lane, gtuType);
259 pos += actualHeadway;
260 }
261 }
262 }
263 catch (Exception exception)
264 {
265 exception.printStackTrace();
266 }
267 }
268
269
270
271
272
273
274
275
276
277
278
279
280 protected final void generateGTU(final Length initialPosition, final Lane lane, final GTUType gtuType)
281 throws GTUException, NetworkException, SimRuntimeException, OTSGeometryException, InputParameterException
282 {
283
284 boolean generateTruck = this.stream.nextDouble() > this.carProbability;
285 Length vehicleLength = new Length(generateTruck ? 15 : 4, METER);
286 LaneBasedIndividualGTU gtu = new LaneBasedIndividualGTU("" + (++this.carsCreated), gtuType, vehicleLength,
287 new Length(1.8, METER), new Speed(200, KM_PER_HOUR), vehicleLength.times(0.5), this.simulator, this.network);
288 gtu.setParameters(generateTruck ? this.parametersTruck : this.parametersCar);
289 gtu.setNoLaneChangeDistance(Length.ZERO);
290 gtu.setInstantaneousLaneChange(!((boolean) getInputParameter("generic.gradualLaneChange")));
291 gtu.setMaximumAcceleration(Acceleration.instantiateSI(3.0));
292 gtu.setMaximumDeceleration(Acceleration.instantiateSI(-8.0));
293
294
295 LaneBasedStrategicalPlanner strategicalPlanner;
296 Route route = null;
297 if (!generateTruck)
298 {
299 strategicalPlanner = this.strategicalPlannerGeneratorCars.create(gtu, route, null, null);
300 }
301 else
302 {
303 strategicalPlanner = this.strategicalPlannerGeneratorTrucks.create(gtu, route, null, null);
304 }
305
306
307 Set<DirectedLanePosition> initialPositions = new LinkedHashSet<>(1);
308 initialPositions.add(new DirectedLanePosition(lane, initialPosition, GTUDirectionality.DIR_PLUS));
309 Speed initialSpeed = new Speed(0, KM_PER_HOUR);
310 gtu.init(strategicalPlanner, initialPositions, initialSpeed);
311 }
312
313
314 @Override
315 public OTSRoadNetwork getNetwork()
316 {
317 return this.network;
318 }
319
320
321
322
323 public final Length getMinimumDistance()
324 {
325 return this.minimumDistance;
326 }
327
328
329
330
331
332
333 public void stopSimulator(final DEVSSimulatorInterface.TimeDoubleUnit theSimulator, final String errorMessage)
334 {
335 System.out.println("Error: " + errorMessage);
336 try
337 {
338 if (theSimulator.isStartingOrRunning())
339 {
340 theSimulator.stop();
341 }
342 }
343 catch (SimRuntimeException exception)
344 {
345 exception.printStackTrace();
346 }
347 throw new Error(errorMessage);
348 }
349
350
351 @Override
352 public Serializable getSourceId()
353 {
354 return "CircularRoadModel";
355 }
356
357 }