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