Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2012-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_SmartSK.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @author Peter Wagner
19 : /// @date Tue, 05 Jun 2012
20 : ///
21 : // A smarter SK
22 : /****************************************************************************/
23 : #include <config.h>
24 :
25 : #include <map>
26 : #include <microsim/MSVehicle.h>
27 : #include <microsim/MSLane.h>
28 : #include "MSCFModel_SmartSK.h"
29 : #include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
30 : #include <utils/common/RandHelper.h>
31 : #include <utils/xml/SUMOSAXAttributes.h>
32 :
33 : //#define SmartSK_DEBUG
34 :
35 : // ===========================================================================
36 : // method definitions
37 : // ===========================================================================
38 18 : MSCFModel_SmartSK::MSCFModel_SmartSK(const MSVehicleType* vtype) :
39 : // check whether setting these variables here with default values is ''good'' SUMO design
40 : // double tmp1=0.0, double tmp2=5.0, double tmp3=0.0, double tmp4, double tmp5)
41 : MSCFModel(vtype),
42 18 : myDawdle(vtype->getParameter().getCFParam(SUMO_ATTR_SIGMA, SUMOVTypeParameter::getDefaultImperfection(vtype->getParameter().vehicleClass))),
43 18 : myTauDecel(myDecel * myHeadwayTime),
44 18 : myTmp1(vtype->getParameter().getCFParam(SUMO_ATTR_TMP1, 1.0)),
45 18 : myTmp2(vtype->getParameter().getCFParam(SUMO_ATTR_TMP2, 1.0)),
46 18 : myTmp3(vtype->getParameter().getCFParam(SUMO_ATTR_TMP3, 1.0)),
47 18 : myTmp4(vtype->getParameter().getCFParam(SUMO_ATTR_TMP4, 1.0)),
48 36 : myTmp5(vtype->getParameter().getCFParam(SUMO_ATTR_TMP5, 1.0)) {
49 : // the variable tmp1 is the acceleration delay time, e.g. two seconds (or something like this).
50 : // for use in the upate process, a rule like if (v<myTmp1) vsafe = 0; is needed.
51 : // To have this, we have to transform myTmp1 (which is a time) into an equivalent speed. This is done by the
52 : // using the vsafe formula and computing:
53 : // v(t=myTmp1) = -myTauDecel + sqrt(myTauDecel*myTauDecel + accel*(accel + decel)*t*t + accel*decel*t*TS);
54 18 : double t = myTmp1;
55 18 : myS2Sspeed = -myTauDecel + sqrt(myTauDecel * myTauDecel + myAccel * (myAccel + myDecel) * t * t + myAccel * myDecel * t * TS);
56 : #ifdef SmartSK_DEBUG
57 : std::cout << "# s2s-speed: " << myS2Sspeed << std::endl;
58 : #endif
59 18 : if (myS2Sspeed > 5.0) {
60 0 : myS2Sspeed = 5.0;
61 : }
62 : // double maxDeltaGap = -0.5*ACCEL2DIST(myDecel + myAccel);
63 18 : maxDeltaGap = -0.5 * (myDecel + myAccel) * TS * TS;
64 : #ifdef SmartSK_DEBUG
65 : std::cout << "# maxDeltaGap = " << maxDeltaGap << std::endl;
66 : #endif
67 18 : myTmp2 = TS / myTmp2;
68 18 : myTmp3 = sqrt(TS) * myTmp3;
69 18 : }
70 :
71 :
72 36 : MSCFModel_SmartSK::~MSCFModel_SmartSK() {}
73 :
74 :
75 : void
76 10 : MSCFModel_SmartSK::SSKVehicleVariables::saveState(OutputDevice& out, const MSCFModel& /*cfm*/) const {
77 10 : out.openTag(SUMO_TAG_CFM_VARIABLES);
78 10 : out.writeAttr(SUMO_ATTR_ID, "SmartSK");
79 10 : std::ostringstream internals;
80 10 : internals << gOld << " ";
81 10 : internals << myHeadway << " ";
82 10 : internals << ggOld.size() << " ";
83 10 : for (auto item : ggOld) {
84 0 : internals << item.first << " " << item.second << " ";
85 : }
86 10 : out.writeAttr(SUMO_ATTR_STATE, internals.str());
87 10 : out.closeTag();
88 10 : }
89 :
90 :
91 : void
92 10 : MSCFModel_SmartSK::SSKVehicleVariables::loadState(const SUMOSAXAttributes& attrs) {
93 10 : bool ok = true;
94 10 : const std::string cfmID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
95 10 : if (cfmID != "SmartSK") {
96 0 : throw ProcessError(TLF("incompatible carFollowModel '%' when loading state for SmartSK", cfmID));
97 : }
98 10 : std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
99 10 : bis >> gOld;
100 10 : bis >> myHeadway;
101 : int ggOldSize;
102 10 : bis >> ggOldSize;
103 10 : for (int i = 0; i < ggOldSize; i++) {
104 : int k;
105 : double v;
106 0 : bis >> k;
107 : bis >> v;
108 0 : ggOld[k] = v;
109 : }
110 20 : }
111 :
112 :
113 : double
114 22926 : MSCFModel_SmartSK::finalizeSpeed(MSVehicle* const veh, double vPos) const {
115 22926 : const double vNext = MSCFModel::finalizeSpeed(veh, vPos);
116 22926 : updateMyHeadway(veh);
117 : SSKVehicleVariables* vars = (SSKVehicleVariables*)veh->getCarFollowVariables();
118 : #ifdef SmartSK_DEBUG
119 : if (vars->ggOld.size() > 1) {
120 : std::cout << "# more than one entry in ggOld list. Speed is " << vPos << ", corresponding dist is " << vars->ggOld[(int) vPos] << "\n";
121 : for (std::map<int, double>::iterator I = vars->ggOld.begin(); I != vars->ggOld.end(); I++) {
122 : std::cout << "# " << (*I).first << ' ' << (*I).second << std::endl;
123 : }
124 : }
125 : #endif
126 22926 : vars->gOld = vars->ggOld[(int) vPos];
127 : vars->ggOld.clear();
128 22926 : return vNext;
129 : }
130 :
131 : double
132 21050 : MSCFModel_SmartSK::followSpeed(const MSVehicle* const veh, double speed, double gap, double predSpeed, double /*predMaxDecel*/, const MSVehicle* const /*pred*/, const CalcReason /*usage*/) const {
133 : SSKVehicleVariables* vars = (SSKVehicleVariables*)veh->getCarFollowVariables();
134 :
135 : // if (((gap - vars->gOld) < maxDeltaGap) && (speed>=5.0) && gap>=5.0) {
136 21050 : if ((gap - vars->gOld) < maxDeltaGap) {
137 588 : double tTauTest = gap / speed;
138 : // allow headway only to decrease only, never to increase. Increase is handled automatically by the headway dynamics in finalizeSpeed()!!!
139 588 : if ((tTauTest < vars->myHeadway) && (tTauTest > TS)) {
140 2 : vars->myHeadway = tTauTest;
141 : }
142 : }
143 :
144 21050 : double vsafe = _vsafe(veh, gap, predSpeed);
145 21050 : if ((speed <= 0.0) && (vsafe < myS2Sspeed)) {
146 : vsafe = 0;
147 : }
148 :
149 42100 : double vNew = MAX2(getSpeedAfterMaxDecel(speed), MIN2(vsafe, maxNextSpeed(speed, veh)));
150 : // there must be a better place to do the following assignment!!!
151 21050 : vars->gOld = gap;
152 21050 : vars->ggOld[(int)vNew] = gap;
153 21050 : return vNew;
154 : }
155 :
156 : double
157 28460 : MSCFModel_SmartSK::stopSpeed(const MSVehicle* const veh, const double speed, double gap, double /*decel*/, const CalcReason /*usage*/) const {
158 : SSKVehicleVariables* vars = (SSKVehicleVariables*)veh->getCarFollowVariables();
159 :
160 : // if (((gap - vars->gOld) < maxDeltaGap) && (speed>=5.0) && gap>=5.0) {
161 28460 : if ((gap - vars->gOld) < maxDeltaGap) {
162 6 : double tTauTest = gap / speed;
163 : // allow headway only to decrease only, never to increase. Increase is handled automatically by the headway dynamics in finalizeSpeed()!!!
164 6 : if ((tTauTest < vars->myHeadway) && (tTauTest > TS)) {
165 0 : vars->myHeadway = tTauTest;
166 : }
167 : }
168 :
169 56920 : return MAX2(getSpeedAfterMaxDecel(speed), MIN2(_vsafe(veh, gap, 0), maxNextSpeed(speed, veh)));
170 : }
171 :
172 : double
173 22926 : MSCFModel_SmartSK::patchSpeedBeforeLC(const MSVehicle* veh, double /*vMin*/, double /*vMax*/) const {
174 22926 : return dawdle(veh->getSpeed(), veh->getRNG());
175 : }
176 :
177 : double
178 22926 : MSCFModel_SmartSK::dawdle(double speed, SumoRNG* rng) const {
179 22926 : return MAX2(0., speed - ACCEL2SPEED(myDawdle * myAccel * RandHelper::rand(rng)));
180 : }
181 :
182 :
183 : /** Returns the SK-vsafe. */
184 49510 : double MSCFModel_SmartSK::_vsafe(const MSVehicle* const veh, double gap, double predSpeed) const {
185 49510 : if (predSpeed == 0 && gap < 0.01) {
186 : return 0;
187 : }
188 : SSKVehicleVariables* vars = (SSKVehicleVariables*)veh->getCarFollowVariables();
189 : // this is the most obvious change to the normal SK: the model uses the variable vars->myHeadway instead of the constant
190 : // myHeadwayTime as the "desired headway" tau
191 49510 : double bTau = myDecel * (vars->myHeadway);
192 : double vsafe = (double)(-1. * bTau
193 49510 : + sqrt(
194 49510 : bTau * bTau
195 49510 : + (predSpeed * predSpeed)
196 49510 : + (2. * myDecel * gap)
197 49510 : ));
198 : assert(vsafe >= 0);
199 49510 : return vsafe;
200 : }
201 :
202 :
203 : MSCFModel*
204 0 : MSCFModel_SmartSK::duplicate(const MSVehicleType* vtype) const {
205 0 : return new MSCFModel_SmartSK(vtype);
206 : }
|