Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2011-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 MSInstantInductLoop.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @date 2011-09.08
19 : ///
20 : // An instantaneous induction loop
21 : /****************************************************************************/
22 : #include <config.h>
23 :
24 : #include "MSInstantInductLoop.h"
25 : #include <cassert>
26 : #include <numeric>
27 : #include <utility>
28 : #ifdef HAVE_FOX
29 : #include <utils/common/ScopedLocker.h>
30 : #endif
31 : #include <utils/common/WrappingCommand.h>
32 : #include <utils/common/ToString.h>
33 : #include <microsim/MSEventControl.h>
34 : #include <microsim/MSLane.h>
35 : #include <microsim/MSVehicle.h>
36 : #include <microsim/MSNet.h>
37 : #include <utils/common/MsgHandler.h>
38 : #include <utils/common/UtilExceptions.h>
39 : #include <utils/common/StringUtils.h>
40 : #include <utils/iodevices/OutputDevice.h>
41 :
42 :
43 : // ===========================================================================
44 : // method definitions
45 : // ===========================================================================
46 1027 : MSInstantInductLoop::MSInstantInductLoop(const std::string& id,
47 : OutputDevice& od, MSLane* const lane, double positionInMeters,
48 : const std::string name, const std::string& vTypes,
49 : const std::string& nextEdges,
50 1027 : int detectPersons) :
51 : MSMoveReminder(id, lane),
52 : MSDetectorFileOutput(id, vTypes, nextEdges, detectPersons),
53 1027 : myName(name),
54 1027 : myOutputDevice(od),
55 2054 : myPosition(positionInMeters), myLastExitTime(-1) {
56 : assert(myPosition >= 0 && myPosition <= myLane->getLength());
57 1027 : writeXMLDetectorProlog(od);
58 1027 : }
59 :
60 :
61 1932 : MSInstantInductLoop::~MSInstantInductLoop() {
62 1932 : }
63 :
64 : bool
65 20832 : MSInstantInductLoop::notifyEnter(SUMOTrafficObject& veh, Notification reason, const MSLane* /*enteredLane*/) {
66 : // vehicles must be kept if the "inductionloop" wants to detect passeengers
67 20832 : if (!vehicleApplies(veh)) {
68 : return false;
69 : }
70 19828 : if (reason != NOTIFICATION_JUNCTION) { // the junction case is handled in notifyMove
71 1788 : if (veh.getBackPositionOnLane(myLane) >= myPosition) {
72 : return false;
73 : }
74 1775 : if (veh.getPositionOnLane() >= myPosition) {
75 11 : double entryTime = SIMTIME;
76 11 : if (myLastExitTime >= 0) {
77 4 : write("enter", entryTime, veh, veh.getSpeed(), "gap", entryTime - myLastExitTime);
78 : } else {
79 7 : write("enter", entryTime, veh, veh.getSpeed());
80 : }
81 11 : myEntryTimes[&veh] = entryTime;
82 : }
83 : }
84 : return true;
85 : }
86 :
87 :
88 : bool
89 95615 : MSInstantInductLoop::notifyMove(SUMOTrafficObject& veh, double oldPos,
90 : double newPos, double newSpeed) {
91 95615 : if (!vehicleApplies(veh)) {
92 : return false;
93 : }
94 95579 : if (newPos < myPosition) {
95 : // detector not reached yet
96 : return true;
97 : }
98 : #ifdef HAVE_FOX
99 26571 : ScopedLocker<> lock(myNotificationMutex, MSGlobals::gNumSimThreads > 1);
100 : #endif
101 :
102 26571 : const double oldSpeed = veh.getPreviousSpeed();
103 : double enterSpeed = MSGlobals::gSemiImplicitEulerUpdate ? newSpeed : oldSpeed; // NOTE: For the euler update, the vehicle is assumed to travel at constant speed for the whole time step
104 :
105 26571 : if (newPos >= myPosition && oldPos < myPosition/* && static_cast<MSVehicle&>(veh).getLane() == myLane*/) {
106 17466 : const double timeBeforeEnter = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
107 17466 : const double entryTime = SIMTIME - TS + timeBeforeEnter;
108 17466 : enterSpeed = MSCFModel::speedAfterTime(timeBeforeEnter, oldSpeed, newPos - oldPos);
109 17466 : if (myLastExitTime >= 0) {
110 17122 : write("enter", entryTime, veh, enterSpeed, "gap", entryTime - myLastExitTime);
111 : } else {
112 344 : write("enter", entryTime, veh, enterSpeed);
113 : }
114 17466 : myEntryTimes[&veh] = entryTime;
115 : }
116 26571 : const double newBackPos = newPos - veh.getVehicleType().getLength();
117 26571 : const double oldBackPos = oldPos - veh.getVehicleType().getLength();
118 26571 : if (newBackPos > myPosition) {
119 : std::map<SUMOTrafficObject*, double>::iterator i = myEntryTimes.find(&veh);
120 17474 : if (i != myEntryTimes.end()) {
121 : // vehicle passed the detector
122 17474 : const double timeBeforeLeave = MSCFModel::passingTime(oldBackPos, myPosition, newBackPos, oldSpeed, newSpeed);
123 17474 : const double leaveTime = SIMTIME - TS + timeBeforeLeave;
124 17474 : write("leave", leaveTime, veh, newSpeed, "occupancy", leaveTime - (*i).second);
125 : myEntryTimes.erase(i);
126 17474 : myLastExitTime = leaveTime;
127 : }
128 : return false;
129 : }
130 : // vehicle stays on the detector
131 9097 : write("stay", SIMTIME, veh, newSpeed);
132 : return true;
133 : }
134 :
135 :
136 : void
137 44051 : MSInstantInductLoop::write(const char* state, double t, SUMOTrafficObject& veh, double speed, const char* add, double addValue) {
138 44051 : if (!myOutputDevice.isNull()) {
139 87982 : myOutputDevice.openTag("instantOut").writeAttr(
140 87982 : "id", getID()).writeAttr("time", toString(t)).writeAttr("state", state).writeAttr(
141 175964 : "vehID", veh.getID()).writeAttr("speed", toString(speed)).writeAttr(
142 175964 : "length", toString(veh.getVehicleType().getLength())).writeAttr(
143 43991 : "type", veh.getVehicleType().getID());
144 43991 : if (add != nullptr) {
145 69128 : myOutputDevice.writeAttr(add, toString(addValue));
146 : }
147 87982 : myOutputDevice.closeTag();
148 : }
149 44051 : }
150 :
151 :
152 : bool
153 5597 : MSInstantInductLoop::notifyLeave(SUMOTrafficObject& veh, double /* lastPos */, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
154 5597 : if (reason == MSMoveReminder::NOTIFICATION_JUNCTION) {
155 : // vehicle might have jumped over detector at the end of the lane. we need
156 : // one more notifyMove to register it
157 : return true;
158 : }
159 : std::map<SUMOTrafficObject*, double>::iterator i = myEntryTimes.find(&veh);
160 1305 : if (i != myEntryTimes.end()) {
161 3 : write("leave", SIMTIME, veh, veh.getSpeed());
162 : myEntryTimes.erase(i);
163 : }
164 : return false;
165 : }
166 :
167 :
168 : void
169 1027 : MSInstantInductLoop::writeXMLDetectorProlog(OutputDevice& dev) const {
170 2054 : dev.writeXMLHeader("instantE1", "instant_e1_file.xsd");
171 1027 : }
172 :
173 :
174 : /****************************************************************************/
|