1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file MSVehicleType.cpp
11 /// @author Christian Roessel
12 /// @author Daniel Krajzewicz
13 /// @author Jakob Erdmann
14 /// @author Thimor Bohn
15 /// @author Michael Behrisch
16 /// @date Tue, 06 Mar 2001
17 /// @version $Id$
18 ///
19 // The car-following model and parameter
20 /****************************************************************************/
21
22
23 // ===========================================================================
24 // included modules
25 // ===========================================================================
26 #include <config.h>
27
28 #include <cassert>
29 #include <utils/iodevices/BinaryInputDevice.h>
30 #include <utils/options/OptionsCont.h>
31 #include <utils/common/FileHelpers.h>
32 #include <utils/common/RandHelper.h>
33 #include <utils/common/StringUtils.h>
34 #include <utils/vehicle/SUMOVTypeParameter.h>
35 #include <microsim/cfmodels/MSCFModel_Rail.h>
36 #include "MSNet.h"
37 #include "cfmodels/MSCFModel_IDM.h"
38 #include "cfmodels/MSCFModel_Kerner.h"
39 #include "cfmodels/MSCFModel_Krauss.h"
40 #include "cfmodels/MSCFModel_KraussOrig1.h"
41 #include "cfmodels/MSCFModel_KraussPS.h"
42 #include "cfmodels/MSCFModel_KraussX.h"
43 #include "cfmodels/MSCFModel_SmartSK.h"
44 #include "cfmodels/MSCFModel_Daniel1.h"
45 #include "cfmodels/MSCFModel_PWag2009.h"
46 #include "cfmodels/MSCFModel_Wiedemann.h"
47 #include "cfmodels/MSCFModel_ACC.h"
48 #include "cfmodels/MSCFModel_CACC.h"
49 #include "MSVehicleControl.h"
50 #include "cfmodels/MSCFModel_CC.h"
51 #include "MSVehicleType.h"
52
53
54 // ===========================================================================
55 // static members
56 // ===========================================================================
57 int MSVehicleType::myNextIndex = 0;
58
59
60 // ===========================================================================
61 // method definitions
62 // ===========================================================================
MSVehicleType(const SUMOVTypeParameter & parameter)63 MSVehicleType::MSVehicleType(const SUMOVTypeParameter& parameter)
64 : myParameter(parameter), myWarnedActionStepLengthTauOnce(false), myIndex(myNextIndex++), myCarFollowModel(nullptr), myOriginalType(nullptr) {
65 assert(getLength() > 0);
66 assert(getMaxSpeed() > 0);
67
68 // Check if actionStepLength was set by user, if not init to global default
69 if (!myParameter.wasSet(VTYPEPARS_ACTIONSTEPLENGTH_SET)) {
70 myParameter.actionStepLength = MSGlobals::gActionStepLength;
71 }
72 myCachedActionStepLengthSecs = STEPS2TIME(myParameter.actionStepLength);
73 }
74
75
~MSVehicleType()76 MSVehicleType::~MSVehicleType() {
77 delete myCarFollowModel;
78 }
79
80
81 double
computeChosenSpeedDeviation(std::mt19937 * rng,const double minDev) const82 MSVehicleType::computeChosenSpeedDeviation(std::mt19937* rng, const double minDev) const {
83 return MAX2(minDev, myParameter.speedFactor.sample(rng));
84 }
85
86
87 // ------------ Setter methods
88 void
setLength(const double & length)89 MSVehicleType::setLength(const double& length) {
90 if (myOriginalType != nullptr && length < 0) {
91 myParameter.length = myOriginalType->getLength();
92 } else {
93 myParameter.length = length;
94 }
95 myParameter.parametersSet |= VTYPEPARS_LENGTH_SET;
96 }
97
98
99 void
setHeight(const double & height)100 MSVehicleType::setHeight(const double& height) {
101 if (myOriginalType != nullptr && height < 0) {
102 myParameter.height = myOriginalType->getHeight();
103 } else {
104 myParameter.height = height;
105 }
106 myParameter.parametersSet |= VTYPEPARS_HEIGHT_SET;
107 }
108
109
110 void
setMinGap(const double & minGap)111 MSVehicleType::setMinGap(const double& minGap) {
112 if (myOriginalType != nullptr && minGap < 0) {
113 myParameter.minGap = myOriginalType->getMinGap();
114 } else {
115 myParameter.minGap = minGap;
116 }
117 myParameter.parametersSet |= VTYPEPARS_MINGAP_SET;
118 }
119
120
121 void
setMinGapLat(const double & minGapLat)122 MSVehicleType::setMinGapLat(const double& minGapLat) {
123 if (myOriginalType != nullptr && minGapLat < 0) {
124 myParameter.minGapLat = myOriginalType->getMinGapLat();
125 } else {
126 myParameter.minGapLat = minGapLat;
127 }
128 myParameter.parametersSet |= VTYPEPARS_MINGAP_LAT_SET;
129 }
130
131
132 void
setMaxSpeed(const double & maxSpeed)133 MSVehicleType::setMaxSpeed(const double& maxSpeed) {
134 if (myOriginalType != nullptr && maxSpeed < 0) {
135 myParameter.maxSpeed = myOriginalType->getMaxSpeed();
136 } else {
137 myParameter.maxSpeed = maxSpeed;
138 }
139 myParameter.parametersSet |= VTYPEPARS_MAXSPEED_SET;
140 }
141
142
143 void
setMaxSpeedLat(const double & maxSpeedLat)144 MSVehicleType::setMaxSpeedLat(const double& maxSpeedLat) {
145 if (myOriginalType != nullptr && maxSpeedLat < 0) {
146 myParameter.maxSpeedLat = myOriginalType->getMaxSpeedLat();
147 } else {
148 myParameter.maxSpeedLat = maxSpeedLat;
149 }
150 myParameter.parametersSet |= VTYPEPARS_MAXSPEED_LAT_SET;
151 }
152
153
154 void
setVClass(SUMOVehicleClass vclass)155 MSVehicleType::setVClass(SUMOVehicleClass vclass) {
156 myParameter.vehicleClass = vclass;
157 myParameter.parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
158 }
159
160 void
setPreferredLateralAlignment(LateralAlignment latAlignment)161 MSVehicleType::setPreferredLateralAlignment(LateralAlignment latAlignment) {
162 myParameter.latAlignment = latAlignment;
163 myParameter.parametersSet |= VTYPEPARS_LATALIGNMENT_SET;
164 }
165
166
167 void
setDefaultProbability(const double & prob)168 MSVehicleType::setDefaultProbability(const double& prob) {
169 if (myOriginalType != nullptr && prob < 0) {
170 myParameter.defaultProbability = myOriginalType->getDefaultProbability();
171 } else {
172 myParameter.defaultProbability = prob;
173 }
174 myParameter.parametersSet |= VTYPEPARS_PROBABILITY_SET;
175 }
176
177
178 void
setSpeedFactor(const double & factor)179 MSVehicleType::setSpeedFactor(const double& factor) {
180 if (myOriginalType != nullptr && factor < 0) {
181 myParameter.speedFactor.getParameter()[0] = myOriginalType->myParameter.speedFactor.getParameter()[0];
182 } else {
183 myParameter.speedFactor.getParameter()[0] = factor;
184 }
185 myParameter.parametersSet |= VTYPEPARS_SPEEDFACTOR_SET;
186 }
187
188
189 void
setSpeedDeviation(const double & dev)190 MSVehicleType::setSpeedDeviation(const double& dev) {
191 if (myOriginalType != nullptr && dev < 0) {
192 myParameter.speedFactor.getParameter()[1] = myOriginalType->myParameter.speedFactor.getParameter()[1];
193 } else {
194 myParameter.speedFactor.getParameter()[1] = dev;
195 }
196 myParameter.parametersSet |= VTYPEPARS_SPEEDFACTOR_SET;
197 }
198
199
200 void
setActionStepLength(const SUMOTime actionStepLength,bool resetActionOffset)201 MSVehicleType::setActionStepLength(const SUMOTime actionStepLength, bool resetActionOffset) {
202 assert(actionStepLength >= 0.);
203 myParameter.parametersSet |= VTYPEPARS_ACTIONSTEPLENGTH_SET;
204
205 if (myParameter.actionStepLength == actionStepLength) {
206 return;
207 }
208
209 SUMOTime previousActionStepLength = myParameter.actionStepLength;
210 myParameter.actionStepLength = actionStepLength;
211 myCachedActionStepLengthSecs = STEPS2TIME(myParameter.actionStepLength);
212 check();
213
214 if (isVehicleSpecific()) {
215 // don't perform vehicle lookup for singular vtype
216 return;
217 }
218
219 // For non-singular vType reset all vehicle's actionOffsets
220 // Iterate through vehicles
221 MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
222 for (auto vehIt = vc.loadedVehBegin(); vehIt != vc.loadedVehEnd(); ++vehIt) {
223 MSVehicle* veh = static_cast<MSVehicle*>(vehIt->second);
224 if (&veh->getVehicleType() == this) {
225 // Found vehicle of this type. Perform requested actionOffsetReset
226 if (resetActionOffset) {
227 veh->resetActionOffset();
228 } else {
229 veh->updateActionOffset(previousActionStepLength, actionStepLength);
230 }
231 }
232 }
233 }
234
235
236 void
setEmissionClass(SUMOEmissionClass eclass)237 MSVehicleType::setEmissionClass(SUMOEmissionClass eclass) {
238 myParameter.emissionClass = eclass;
239 myParameter.parametersSet |= VTYPEPARS_EMISSIONCLASS_SET;
240 }
241
242
243 void
setColor(const RGBColor & color)244 MSVehicleType::setColor(const RGBColor& color) {
245 myParameter.color = color;
246 myParameter.parametersSet |= VTYPEPARS_COLOR_SET;
247 }
248
249
250 void
setWidth(const double & width)251 MSVehicleType::setWidth(const double& width) {
252 if (myOriginalType != nullptr && width < 0) {
253 myParameter.width = myOriginalType->getWidth();
254 } else {
255 myParameter.width = width;
256 }
257 myParameter.parametersSet |= VTYPEPARS_WIDTH_SET;
258 }
259
260 void
setImpatience(const double impatience)261 MSVehicleType::setImpatience(const double impatience) {
262 if (myOriginalType != nullptr && impatience < 0) {
263 myParameter.impatience = myOriginalType->getImpatience();
264 } else {
265 myParameter.impatience = impatience;
266 }
267 myParameter.parametersSet |= VTYPEPARS_IMPATIENCE_SET;
268 }
269
270
271 void
setShape(SUMOVehicleShape shape)272 MSVehicleType::setShape(SUMOVehicleShape shape) {
273 myParameter.shape = shape;
274 myParameter.parametersSet |= VTYPEPARS_SHAPE_SET;
275 }
276
277
278
279 // ------------ Static methods for building vehicle types
280 MSVehicleType*
build(SUMOVTypeParameter & from)281 MSVehicleType::build(SUMOVTypeParameter& from) {
282 MSVehicleType* vtype = new MSVehicleType(from);
283 const double decel = from.getCFParam(SUMO_ATTR_DECEL, SUMOVTypeParameter::getDefaultDecel(from.vehicleClass));
284 const double emergencyDecel = from.getCFParam(SUMO_ATTR_EMERGENCYDECEL, SUMOVTypeParameter::getDefaultEmergencyDecel(from.vehicleClass, decel, MSGlobals::gDefaultEmergencyDecel));
285 // by default decel and apparentDecel are identical
286 const double apparentDecel = from.getCFParam(SUMO_ATTR_APPARENTDECEL, decel);
287
288 if (emergencyDecel < decel) {
289 WRITE_WARNING("Value of 'emergencyDecel' (" + toString(emergencyDecel) + ") should be higher than 'decel' (" + toString(decel) + ") for vType '" + from.id + "'.");
290 }
291 if (emergencyDecel < apparentDecel) {
292 WRITE_WARNING("Value of 'emergencyDecel' (" + toString(emergencyDecel) + ") is lower than 'apparentDecel' (" + toString(apparentDecel) + ") for vType '" + from.id + "' may cause collisions.");
293 }
294
295 switch (from.cfModel) {
296 case SUMO_TAG_CF_IDM:
297 vtype->myCarFollowModel = new MSCFModel_IDM(vtype, false);
298 break;
299 case SUMO_TAG_CF_IDMM:
300 vtype->myCarFollowModel = new MSCFModel_IDM(vtype, true);
301 break;
302 case SUMO_TAG_CF_BKERNER:
303 vtype->myCarFollowModel = new MSCFModel_Kerner(vtype);
304 break;
305 case SUMO_TAG_CF_KRAUSS_ORIG1:
306 vtype->myCarFollowModel = new MSCFModel_KraussOrig1(vtype);
307 break;
308 case SUMO_TAG_CF_KRAUSS_PLUS_SLOPE:
309 vtype->myCarFollowModel = new MSCFModel_KraussPS(vtype);
310 break;
311 case SUMO_TAG_CF_KRAUSSX:
312 vtype->myCarFollowModel = new MSCFModel_KraussX(vtype);
313 break;
314 case SUMO_TAG_CF_SMART_SK:
315 vtype->myCarFollowModel = new MSCFModel_SmartSK(vtype);
316 break;
317 case SUMO_TAG_CF_DANIEL1:
318 vtype->myCarFollowModel = new MSCFModel_Daniel1(vtype);
319 break;
320 case SUMO_TAG_CF_PWAGNER2009:
321 vtype->myCarFollowModel = new MSCFModel_PWag2009(vtype);
322 break;
323 case SUMO_TAG_CF_WIEDEMANN:
324 vtype->myCarFollowModel = new MSCFModel_Wiedemann(vtype);
325 break;
326 case SUMO_TAG_CF_RAIL:
327 vtype->myCarFollowModel = new MSCFModel_Rail(vtype);
328 break;
329 case SUMO_TAG_CF_ACC:
330 vtype->myCarFollowModel = new MSCFModel_ACC(vtype);
331 break;
332 case SUMO_TAG_CF_CACC:
333 vtype->myCarFollowModel = new MSCFModel_CACC(vtype);
334 break;
335 case SUMO_TAG_CF_CC:
336 vtype->myCarFollowModel = new MSCFModel_CC(vtype);
337 break;
338 case SUMO_TAG_CF_KRAUSS:
339 default:
340 vtype->myCarFollowModel = new MSCFModel_Krauss(vtype);
341 break;
342 }
343 // init further param values
344 vtype->initParameters();
345 vtype->check();
346 return vtype;
347 }
348
349
350 MSVehicleType*
buildSingularType(const std::string & id) const351 MSVehicleType::buildSingularType(const std::string& id) const {
352 return duplicateType(id, false);
353 }
354
355
356 MSVehicleType*
duplicateType(const std::string & id,bool persistent) const357 MSVehicleType::duplicateType(const std::string& id, bool persistent) const {
358 MSVehicleType* vtype = new MSVehicleType(myParameter);
359 vtype->myParameter.id = id;
360 vtype->myCarFollowModel = myCarFollowModel->duplicate(vtype);
361 if (!persistent) {
362 vtype->myOriginalType = this;
363 }
364 if (!MSNet::getInstance()->getVehicleControl().addVType(vtype)) {
365 std::string singular = persistent ? "" : "singular ";
366 throw ProcessError("could not add " + singular + "type " + vtype->getID());
367 }
368 return vtype;
369 }
370
371 void
check()372 MSVehicleType::check() {
373 if (!myWarnedActionStepLengthTauOnce
374 && myParameter.actionStepLength != DELTA_T
375 && STEPS2TIME(myParameter.actionStepLength) > getCarFollowModel().getHeadwayTime()) {
376 myWarnedActionStepLengthTauOnce = true;
377 std::stringstream s;
378 s << "Given action step length " << STEPS2TIME(myParameter.actionStepLength) << " for vehicle type '" << getID()
379 << "' is larger than its parameter tau (=" << getCarFollowModel().getHeadwayTime() << ")!"
380 << " This may lead to collisions. (This warning is only issued once per vehicle type).";
381 WRITE_WARNING(s.str());
382 }
383 }
384
385 void
setAccel(double accel)386 MSVehicleType::setAccel(double accel) {
387 if (myOriginalType != nullptr && accel < 0) {
388 accel = myOriginalType->getCarFollowModel().getMaxAccel();
389 }
390 myCarFollowModel->setMaxAccel(accel);
391 myParameter.cfParameter[SUMO_ATTR_ACCEL] = toString(accel);
392 }
393
394 void
setDecel(double decel)395 MSVehicleType::setDecel(double decel) {
396 if (myOriginalType != nullptr && decel < 0) {
397 decel = myOriginalType->getCarFollowModel().getMaxDecel();
398 }
399 myCarFollowModel->setMaxDecel(decel);
400 myParameter.cfParameter[SUMO_ATTR_DECEL] = toString(decel);
401 }
402
403 void
setEmergencyDecel(double emergencyDecel)404 MSVehicleType::setEmergencyDecel(double emergencyDecel) {
405 if (myOriginalType != nullptr && emergencyDecel < 0) {
406 emergencyDecel = myOriginalType->getCarFollowModel().getEmergencyDecel();
407 }
408 myCarFollowModel->setEmergencyDecel(emergencyDecel);
409 myParameter.cfParameter[SUMO_ATTR_EMERGENCYDECEL] = toString(emergencyDecel);
410 }
411
412 void
setApparentDecel(double apparentDecel)413 MSVehicleType::setApparentDecel(double apparentDecel) {
414 if (myOriginalType != nullptr && apparentDecel < 0) {
415 apparentDecel = myOriginalType->getCarFollowModel().getApparentDecel();
416 }
417 myCarFollowModel->setApparentDecel(apparentDecel);
418 myParameter.cfParameter[SUMO_ATTR_APPARENTDECEL] = toString(apparentDecel);
419 }
420
421 void
setImperfection(double imperfection)422 MSVehicleType::setImperfection(double imperfection) {
423 if (myOriginalType != nullptr && imperfection < 0) {
424 imperfection = myOriginalType->getCarFollowModel().getImperfection();
425 }
426 myCarFollowModel->setImperfection(imperfection);
427 myParameter.cfParameter[SUMO_ATTR_SIGMA] = toString(imperfection);
428 }
429
430 void
setTau(double tau)431 MSVehicleType::setTau(double tau) {
432 if (myOriginalType != nullptr && tau < 0) {
433 tau = myOriginalType->getCarFollowModel().getHeadwayTime();
434 }
435 myCarFollowModel->setHeadwayTime(tau);
436 myParameter.cfParameter[SUMO_ATTR_TAU] = toString(tau);
437 }
438
439
440 void
initParameters()441 MSVehicleType::initParameters() {
442 if (myParameter.knowsParameter("carriageLength")) {
443 myParameter.carriageLength = StringUtils::toDouble(myParameter.getParameter("carriageLength"));
444 } else if (myParameter.wasSet(VTYPEPARS_SHAPE_SET)) {
445 switch (myParameter.shape) {
446 case SVS_BUS_FLEXIBLE:
447 myParameter.carriageLength = 8.25; // 16.5 overall, 2 modules http://de.wikipedia.org/wiki/Ikarus_180
448 myParameter.carriageGap = 0;
449 break;
450 case SVS_RAIL:
451 myParameter.carriageLength = 24.5; // http://de.wikipedia.org/wiki/UIC-Y-Wagen_%28DR%29
452 break;
453 case SVS_RAIL_CAR:
454 myParameter.carriageLength = 16.85; // 67.4m overall, 4 carriages http://de.wikipedia.org/wiki/DB-Baureihe_423
455 break;
456 case SVS_RAIL_CARGO:
457 myParameter.carriageLength = 13.86; // UIC 571-1 http://de.wikipedia.org/wiki/Flachwagen
458 break;
459 case SVS_TRUCK_SEMITRAILER:
460 myParameter.carriageLength = 13.5;
461 myParameter.locomotiveLength = 2.5;
462 myParameter.carriageGap = 0.5;
463 break;
464 case SVS_TRUCK_1TRAILER:
465 myParameter.carriageLength = 6.75;
466 myParameter.locomotiveLength = 2.5 + 6.75;
467 myParameter.carriageGap = 0.5;
468 break;
469 default:
470 break;
471 }
472 }
473 if (myParameter.knowsParameter("locomotiveLength")) {
474 myParameter.locomotiveLength = StringUtils::toDouble(myParameter.getParameter("locomotiveLength"));
475 } else if (myParameter.locomotiveLength <= 0) {
476 myParameter.locomotiveLength = myParameter.carriageLength;
477 }
478 if (myParameter.knowsParameter("carriageGap")) {
479 myParameter.carriageGap = StringUtils::toDouble(myParameter.getParameter("carriageGap"));
480 }
481 }
482
483 /****************************************************************************/
484
485