Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2025 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 MSRailSignalConstraint.cpp
15 : /// @author Jakob Erdmann
16 : /// @date August 2020
17 : ///
18 : // A constraint on rail signal switching
19 : /****************************************************************************/
20 : #include <config.h>
21 : #include <cassert>
22 : #include <utility>
23 :
24 : #include <utils/xml/SUMOSAXAttributes.h>
25 : #include <utils/common/StringUtils.h>
26 : #include <microsim/MSLane.h>
27 : #include <microsim/MSEdge.h>
28 : #include <microsim/MSLink.h>
29 : #include <microsim/MSNet.h>
30 : #include <microsim/MSVehicleControl.h>
31 : #include "MSRailSignal.h"
32 : #include "MSRailSignalConstraint.h"
33 : #include "MSRailSignalControl.h"
34 :
35 : //#define DEBUG_PASSED
36 : //#define DEBUG_LANE
37 :
38 : // ===========================================================================
39 : // static value definitions
40 : // ===========================================================================
41 : std::map<const MSLane*, MSRailSignalConstraint_Predecessor::PassedTracker*, ComparatorNumericalIdLess> MSRailSignalConstraint_Predecessor::myTrackerLookup;
42 : std::map<std::string, std::string> MSRailSignalConstraint::myTripIdLookup;
43 :
44 : // ===========================================================================
45 : // MSRailSignalConstraint method definitions
46 : // ===========================================================================
47 : void
48 38683 : MSRailSignalConstraint::cleanup() {
49 38683 : MSRailSignalConstraint_Predecessor::cleanup();
50 38683 : }
51 :
52 : void
53 476 : MSRailSignalConstraint::saveState(OutputDevice& out) {
54 952 : if (OptionsCont::getOptions().getBool("save-state.constraints")) {
55 37 : for (MSRailSignal* s : MSRailSignalControl::getInstance().getSignals()) {
56 28 : if (s->getConstraints().size() > 0) {
57 19 : out.openTag(SUMO_TAG_RAILSIGNAL_CONSTRAINTS);
58 19 : out.writeAttr(SUMO_ATTR_ID, s->getID());
59 54 : for (auto item : s->getConstraints()) {
60 70 : for (MSRailSignalConstraint* c : item.second) {
61 35 : c->write(out, item.first);
62 : }
63 : }
64 38 : out.closeTag();
65 : }
66 : }
67 : }
68 476 : MSRailSignalConstraint_Predecessor::saveState(out);
69 476 : }
70 :
71 : void
72 177 : MSRailSignalConstraint::clearState() {
73 177 : MSRailSignalConstraint_Predecessor::clearState();
74 : myTripIdLookup.clear();
75 177 : }
76 :
77 : void
78 7 : MSRailSignalConstraint::clearAll() {
79 31 : for (MSRailSignal* s : MSRailSignalControl::getInstance().getSignals()) {
80 24 : s->removeConstraints();
81 : }
82 : myTripIdLookup.clear();
83 7 : }
84 :
85 :
86 : const SUMOVehicle*
87 20145 : MSRailSignalConstraint::getVeh(const std::string& tripID, bool checkID) {
88 20145 : MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
89 20145 : const std::string& vehID = lookupVehId(tripID);
90 20145 : if (vehID != "") {
91 3750 : SUMOVehicle* veh = c.getVehicle(vehID);
92 3750 : if (veh != nullptr) {
93 : return veh;
94 : }
95 : }
96 29550 : for (MSVehicleControl::constVehIt i = c.loadedVehBegin(); i != c.loadedVehEnd(); ++i) {
97 25677 : SUMOVehicle* veh = i->second;
98 51354 : if (veh->getParameter().getParameter("tripId") == tripID || (checkID && veh->getID() == tripID)) {
99 : return veh;
100 : }
101 : }
102 : return nullptr;
103 : }
104 :
105 : // ===========================================================================
106 : // MSRailSignalConstraint_Predecessor method definitions
107 : // ===========================================================================
108 920 : MSRailSignalConstraint_Predecessor::MSRailSignalConstraint_Predecessor(ConstraintType type, const MSRailSignal* signal, const std::string& tripId, int limit, bool active) :
109 : MSRailSignalConstraint(type),
110 920 : myTripId(tripId),
111 920 : myLimit(limit),
112 920 : myAmActive(active),
113 1840 : myFoeSignal(signal) {
114 1920 : for (const auto& lv : signal->getLinks()) {
115 2000 : for (const MSLink* link : lv) {
116 1000 : MSLane* lane = link->getViaLaneOrLane();
117 1000 : PassedTracker* pt = nullptr;
118 : if (myTrackerLookup.count(lane) == 0) {
119 664 : pt = new PassedTracker(lane);
120 664 : myTrackerLookup[lane] = pt;
121 : } else {
122 336 : pt = myTrackerLookup[lane];
123 : }
124 1000 : pt->raiseLimit(limit);
125 1000 : myTrackers.push_back(pt);
126 : }
127 : }
128 :
129 920 : }
130 :
131 : void
132 38683 : MSRailSignalConstraint_Predecessor::cleanup() {
133 39347 : for (auto item : myTrackerLookup) {
134 664 : delete item.second;
135 : }
136 : myTrackerLookup.clear();
137 38683 : }
138 :
139 : void
140 476 : MSRailSignalConstraint_Predecessor::saveState(OutputDevice& out) {
141 507 : for (auto item : myTrackerLookup) {
142 31 : item.second->saveState(out);
143 : }
144 476 : }
145 :
146 : void
147 4 : MSRailSignalConstraint_Predecessor::loadState(const SUMOSAXAttributes& attrs) {
148 : bool ok;
149 4 : const std::string laneID = attrs.getString(SUMO_ATTR_LANE);
150 4 : const int index = attrs.get<int>(SUMO_ATTR_INDEX, nullptr, ok);
151 4 : const std::vector<std::string>& tripIDs = attrs.get<std::vector<std::string> >(SUMO_ATTR_STATE, nullptr, ok);
152 4 : MSLane* lane = MSLane::dictionary(laneID);
153 4 : if (lane == nullptr) {
154 0 : throw ProcessError(TLF("Unknown lane '%' in loaded state.", laneID));
155 : }
156 : if (myTrackerLookup.count(lane) == 0) {
157 0 : WRITE_WARNINGF(TL("Unknown tracker lane '%' in loaded state."), laneID);
158 : return;
159 : }
160 4 : PassedTracker* tracker = myTrackerLookup[lane];
161 4 : tracker->loadState(index, tripIDs);
162 4 : }
163 :
164 :
165 : void
166 177 : MSRailSignalConstraint_Predecessor::clearState() {
167 197 : for (auto item : myTrackerLookup) {
168 20 : item.second->clearState();
169 : }
170 177 : }
171 :
172 :
173 : bool
174 3261796 : MSRailSignalConstraint_Predecessor::cleared() const {
175 3261796 : if (!myAmActive) {
176 : return true;
177 : }
178 9700836 : for (PassedTracker* pt : myTrackers) {
179 6458489 : if (pt->hasPassed(myTripId, myLimit)) {
180 : return true;
181 : }
182 : }
183 : return false;
184 : }
185 :
186 : std::string
187 3108 : MSRailSignalConstraint_Predecessor::getDescription() const {
188 : // try to retrieve vehicle id that belongs to myTripId
189 : // this may be slow so it should only be used for debugging
190 3108 : const SUMOVehicle* veh = getVeh(myTripId);
191 : std::string vehID;
192 3108 : if (veh != nullptr) {
193 3825 : vehID = " (" + veh->getID() + ")";
194 : }
195 : std::vector<std::string> passedIDs;
196 6216 : for (const std::string& passedTripID : myTrackers.front()->myPassed) {
197 3108 : if (passedTripID == "") {
198 3108 : continue;
199 : }
200 0 : const SUMOVehicle* passedVeh = getVeh(passedTripID);
201 0 : if (passedVeh != nullptr) {
202 0 : passedIDs.push_back(passedVeh->getID());
203 : }
204 : }
205 3108 : std::string passedIDs2 = "";
206 3108 : if (passedIDs.size() > 0) {
207 0 : passedIDs2 = " (" + toString(passedIDs) + ")";
208 : }
209 3108 : std::string params = "";
210 3108 : for (auto item : getParametersMap()) {
211 0 : params += ("\n key=" + item.first + " value=" + item.second);
212 : }
213 6216 : return (toString(getTag()) + " " + myTripId + vehID + " at signal " + myTrackers.front()->getLane()->getEdge().getFromJunction()->getID()
214 15540 : + " passed=" + StringUtils::prune(toString(myTrackers.front()->myPassed)) + passedIDs2 + params);
215 3108 : }
216 :
217 : const SUMOVehicle*
218 17037 : MSRailSignalConstraint_Predecessor::getFoe() const {
219 17037 : return getVeh(myTripId, true);
220 : }
221 :
222 : void
223 2662 : MSRailSignalConstraint::storeTripId(const std::string& tripId, const std::string& vehID) {
224 2662 : myTripIdLookup[tripId] = vehID;
225 2662 : }
226 :
227 : const std::string&
228 20145 : MSRailSignalConstraint::lookupVehId(const std::string& tripId) {
229 20145 : return myTripIdLookup[tripId];
230 : }
231 :
232 : // ===========================================================================
233 : // MSRailSignalConstraint_Predecessor::PassedTracker method definitions
234 : // ===========================================================================
235 :
236 664 : MSRailSignalConstraint_Predecessor::PassedTracker::PassedTracker(MSLane* lane) :
237 664 : MSMoveReminder("PassedTracker_" + lane->getID(), lane, true),
238 664 : myPassed(1, ""),
239 1328 : myLastIndex(-1)
240 664 : { }
241 :
242 : bool
243 503 : MSRailSignalConstraint_Predecessor::PassedTracker::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification /*reason*/, const MSLane* /*enteredLane*/) {
244 503 : myLastIndex = (myLastIndex + 1) % myPassed.size();
245 1006 : myPassed[myLastIndex] = veh.getParameter().getParameter("tripId", veh.getID());
246 : #ifdef DEBUG_PASSED
247 : if (myLane->getID() == DEBUG_LANE) {
248 : std::cout << SIMTIME << " hasPassed " << veh.getID() << " tripId=" << veh.getParameter().getParameter("tripId", veh.getID()) << " index=" << myLastIndex << "\n";
249 : }
250 : #endif
251 503 : return true;
252 : }
253 :
254 : void
255 1004 : MSRailSignalConstraint_Predecessor::PassedTracker::raiseLimit(int limit) {
256 7871 : while (limit > (int)myPassed.size()) {
257 6867 : myPassed.insert(myPassed.begin() + (myLastIndex + 1), "");
258 : }
259 : #ifdef DEBUG_PASSED
260 : if (myLane->getID() == DEBUG_LANE) {
261 : std::cout << " raiseLimit=" << limit << "\n";
262 : }
263 : #endif
264 1004 : }
265 :
266 : bool
267 6458489 : MSRailSignalConstraint_Predecessor::PassedTracker::hasPassed(const std::string& tripId, int limit) const {
268 6458489 : if (myLastIndex < 0) {
269 : return false;
270 : }
271 : int i = myLastIndex;
272 47319 : while (limit > 0) {
273 41483 : if (myPassed[i] == tripId) {
274 : return true;
275 : }
276 22247 : if (i == 0) {
277 5836 : i = (int)myPassed.size() - 1;
278 : } else {
279 16411 : i--;
280 : }
281 22247 : limit--;
282 : }
283 : return false;
284 : }
285 :
286 : void
287 20 : MSRailSignalConstraint_Predecessor::PassedTracker::clearState() {
288 20 : myPassed = std::vector<std::string>(myPassed.size());
289 20 : myLastIndex = 0;
290 20 : }
291 :
292 : void
293 31 : MSRailSignalConstraint_Predecessor::PassedTracker::saveState(OutputDevice& out) {
294 31 : const std::string state = toString(myPassed.back() == ""
295 62 : ? std::vector<std::string>(myPassed.begin(), myPassed.begin() + (myLastIndex + 1))
296 : // wrapped around
297 0 : : myPassed);
298 : // no need to save state if no vehicles have passed this tracker
299 31 : if (state != "") {
300 5 : out.openTag(SUMO_TAG_RAILSIGNAL_CONSTRAINT_TRACKER);
301 5 : out.writeAttr(SUMO_ATTR_LANE, getLane()->getID());
302 5 : out.writeAttr(SUMO_ATTR_INDEX, myLastIndex);
303 5 : out.writeAttr(SUMO_ATTR_STATE, state);
304 10 : out.closeTag();
305 : }
306 31 : }
307 :
308 : void
309 4 : MSRailSignalConstraint_Predecessor::PassedTracker::loadState(int index, const std::vector<std::string>& tripIDs) {
310 4 : raiseLimit((int)tripIDs.size());
311 11 : for (int i = 0; i < (int)tripIDs.size(); i++) {
312 7 : myPassed[i] = tripIDs[i];
313 : }
314 : #ifdef DEBUG_PASSED
315 : if (myLane->getID() == DEBUG_LANE) {
316 : std::cout << " loadState limit=" << tripIDs.size() << " index=" << index << "\n";
317 : for (int i = 0; i < (int)myPassed.size(); i++) {
318 : std::cout << " i=" << i << " passed=" << myPassed[i] << "\n";
319 : }
320 : }
321 : #endif
322 4 : myLastIndex = index;
323 4 : }
324 :
325 :
326 : void
327 53 : MSRailSignalConstraint_Predecessor::write(OutputDevice& out, const std::string& tripId) const {
328 53 : out.openTag(getTag());
329 53 : out.writeAttr(SUMO_ATTR_TRIP_ID, tripId);
330 53 : out.writeAttr(SUMO_ATTR_TLID, myFoeSignal->getID());
331 53 : out.writeAttr(SUMO_ATTR_FOES, myTripId);
332 53 : if (myLimit > 1) {
333 23 : out.writeAttr(SUMO_ATTR_LIMIT, myLimit);
334 : }
335 53 : if (!myAmActive) {
336 22 : out.writeAttr(SUMO_ATTR_ACTIVE, myAmActive);
337 : }
338 53 : writeParams(out);
339 53 : out.closeTag();
340 53 : }
341 :
342 : /****************************************************************************/
|