Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2026-2026 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file MSCFModel_NaSch.cpp
15 : /// @author Jerry Lin
16 : /// @date Thu, 13 Aug 2026
17 : ///
18 : // The Nagel-Schreckenberg (1992) cellular automaton car-following model
19 : /****************************************************************************/
20 : #include <config.h>
21 :
22 : #include <limits>
23 : #include <microsim/MSVehicle.h>
24 : #include <microsim/MSLane.h>
25 : #include <microsim/MSGlobals.h>
26 : #include "MSCFModel_NaSch.h"
27 : #include <utils/common/RandHelper.h>
28 :
29 : // ===========================================================================
30 : // method definitions
31 : // ===========================================================================
32 36 : MSCFModel_NaSch::MSCFModel_NaSch(const MSVehicleType* vtype, double dawdle) :
33 : MSCFModel(vtype),
34 36 : myDawdle(dawdle),
35 : // The classic NaSch cell length is the distance covered by accelerating
36 : // for one simulation step, i.e. the "accel" attribute doubles as the
37 : // cell size (in meters) when using the default step-length of 1s,
38 : // see https://github.com/eclipse-sumo/sumo/issues/12182
39 36 : myCellSpeed(ACCEL2SPEED(myAccel)) {
40 36 : }
41 :
42 :
43 72 : MSCFModel_NaSch::~MSCFModel_NaSch() {}
44 :
45 :
46 : double
47 62418217 : MSCFModel_NaSch::roundToCell(double speed) const {
48 62418217 : if (speed <= 0. || myCellSpeed <= 0.) {
49 : return 0.;
50 : }
51 62249777 : return floor(speed / myCellSpeed + NUMERICAL_EPS) * myCellSpeed;
52 : }
53 :
54 :
55 : double
56 61599074 : MSCFModel_NaSch::vsafe(const MSVehicle* const veh, double speed, double gap) const {
57 61599074 : if (gap < NUMERICAL_EPS) {
58 : return 0.;
59 : }
60 : // NaSch rule 1 (acceleration) followed by rule 2 (slowing down): unlike the
61 : // Krauss-derived models, the leader's speed does not enter the computation at
62 : // all -- the gap alone caps how far ego may move this step, see issue #12182
63 : // ("replace leaderSpeed with gap").
64 61490925 : const double vAccel = maxNextSpeed(speed, veh);
65 61490925 : const double vGapLimited = MIN2(vAccel, DIST2SPEED(gap));
66 61490925 : return roundToCell(MAX2(0., vGapLimited));
67 : }
68 :
69 :
70 : double
71 45375323 : MSCFModel_NaSch::followSpeed(const MSVehicle* const veh, double speed, double gap2pred,
72 : double /*predSpeed*/, double /*predMaxDecel*/, const MSVehicle* const /*pred*/, const CalcReason /*usage*/) const {
73 45375323 : return vsafe(veh, speed, gap2pred);
74 : }
75 :
76 : double
77 7871 : MSCFModel_NaSch::insertionFollowSpeed(const MSVehicle* const veh, double speed, double gap2pred, double /*predSpeed*/, double /*predMaxDecel*/, const MSVehicle* const /*pred*/) const {
78 7871 : return vsafe(veh, speed, gap2pred);
79 : }
80 :
81 :
82 : double
83 16215880 : MSCFModel_NaSch::stopSpeed(const MSVehicle* const veh, const double speed, double gap2pred, double /*decel*/, const CalcReason /*usage*/) const {
84 16215880 : return vsafe(veh, speed, gap2pred);
85 : }
86 :
87 :
88 : double
89 5514132 : MSCFModel_NaSch::patchSpeedBeforeLC(const MSVehicle* veh, double vMin, double vMax) const {
90 : // NaSch rule 3 (randomization): with probability sigma, dawdle by exactly
91 : // one cell -- not a continuously distributed amount as in the Krauss dawdle.
92 5514132 : if (vMax > 0. && myDawdle > 0. && RandHelper::rand(veh->getRNG()) < myDawdle) {
93 927292 : return MAX2(vMin, roundToCell(vMax - myCellSpeed));
94 : }
95 : return vMax;
96 : }
97 :
98 :
99 : double
100 5514132 : MSCFModel_NaSch::minNextSpeedEmergency(double /*speed*/, const MSVehicle* const /*veh*/) const {
101 : // NaSch rule 4 (movement) permits vehicles to stop dead within a single
102 : // step whenever the gap requires it, i.e. emergency deceleration is not
103 : // bounded, see issue #12182 ("do not bound emergency decel").
104 5514132 : if (MSGlobals::gSemiImplicitEulerUpdate) {
105 5514132 : return 0.;
106 : }
107 : return -std::numeric_limits<double>::max();
108 : }
109 :
110 :
111 : MSCFModel*
112 0 : MSCFModel_NaSch::duplicate(const MSVehicleType* vtype) const {
113 0 : return new MSCFModel_NaSch(vtype, myDawdle);
114 : }
115 :
116 :
117 : /****************************************************************************/
|