Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2011-2024 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 954 : MSInstantInductLoop::MSInstantInductLoop(const std::string& id,
47 : OutputDevice& od, MSLane* const lane, double positionInMeters,
48 : const std::string name, const std::string& vTypes,
49 954 : const std::string& nextEdges) :
50 : MSMoveReminder(id, lane),
51 : MSDetectorFileOutput(id, vTypes, nextEdges),
52 954 : myName(name),
53 954 : myOutputDevice(od),
54 1908 : myPosition(positionInMeters), myLastExitTime(-1) {
55 : assert(myPosition >= 0 && myPosition <= myLane->getLength());
56 954 : writeXMLDetectorProlog(od);
57 954 : }
58 :
59 :
60 1780 : MSInstantInductLoop::~MSInstantInductLoop() {
61 1780 : }
62 :
63 :
64 : bool
65 69220 : MSInstantInductLoop::notifyMove(SUMOTrafficObject& veh, double oldPos,
66 : double newPos, double newSpeed) {
67 69220 : if (!vehicleApplies(veh)) {
68 : return false;
69 : }
70 69040 : if (newPos < myPosition) {
71 : // detector not reached yet
72 : return true;
73 : }
74 : #ifdef HAVE_FOX
75 15789 : ScopedLocker<> lock(myNotificationMutex, MSGlobals::gNumSimThreads > 1);
76 : #endif
77 :
78 15789 : const double oldSpeed = veh.getPreviousSpeed();
79 : 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
80 :
81 15789 : if (newPos >= myPosition && oldPos < myPosition/* && static_cast<MSVehicle&>(veh).getLane() == myLane*/) {
82 10287 : const double timeBeforeEnter = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
83 10287 : const double entryTime = SIMTIME - TS + timeBeforeEnter;
84 10287 : enterSpeed = MSCFModel::speedAfterTime(timeBeforeEnter, oldSpeed, newPos - oldPos);
85 10287 : if (myLastExitTime >= 0) {
86 9962 : write("enter", entryTime, veh, enterSpeed, "gap", entryTime - myLastExitTime);
87 : } else {
88 325 : write("enter", entryTime, veh, enterSpeed);
89 : }
90 10287 : myEntryTimes[&veh] = entryTime;
91 : }
92 15789 : const double newBackPos = newPos - veh.getVehicleType().getLength();
93 15789 : const double oldBackPos = oldPos - veh.getVehicleType().getLength();
94 15789 : if (newBackPos > myPosition) {
95 : std::map<SUMOTrafficObject*, double>::iterator i = myEntryTimes.find(&veh);
96 10383 : if (i != myEntryTimes.end()) {
97 : // vehicle passed the detector
98 10284 : const double timeBeforeLeave = MSCFModel::passingTime(oldBackPos, myPosition, newBackPos, oldSpeed, newSpeed);
99 10284 : const double leaveTime = SIMTIME - TS + timeBeforeLeave;
100 10284 : write("leave", leaveTime, veh, newSpeed, "occupancy", leaveTime - (*i).second);
101 : myEntryTimes.erase(i);
102 10284 : myLastExitTime = leaveTime;
103 : }
104 : return false;
105 : }
106 : // vehicle stays on the detector
107 5406 : write("stay", SIMTIME, veh, newSpeed);
108 : return true;
109 : }
110 :
111 :
112 : void
113 25980 : MSInstantInductLoop::write(const char* state, double t, SUMOTrafficObject& veh, double speed, const char* add, double addValue) {
114 25980 : if (!myOutputDevice.isNull()) {
115 51882 : myOutputDevice.openTag("instantOut").writeAttr(
116 103764 : "id", getID()).writeAttr("time", toString(t)).writeAttr("state", state).writeAttr(
117 103764 : "vehID", veh.getID()).writeAttr("speed", toString(speed)).writeAttr(
118 103764 : "length", toString(veh.getVehicleType().getLength())).writeAttr(
119 25941 : "type", veh.getVehicleType().getID());
120 25941 : if (add != nullptr) {
121 40450 : myOutputDevice.writeAttr(add, toString(addValue));
122 : }
123 51882 : myOutputDevice.closeTag();
124 : }
125 25980 : }
126 :
127 :
128 : bool
129 4935 : MSInstantInductLoop::notifyLeave(SUMOTrafficObject& veh, double /* lastPos */, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
130 4935 : if (reason == MSMoveReminder::NOTIFICATION_JUNCTION) {
131 : // vehicle might have jumped over detector at the end of the lane. we need
132 : // one more notifyMove to register it
133 : return true;
134 : }
135 : std::map<SUMOTrafficObject*, double>::iterator i = myEntryTimes.find(&veh);
136 1473 : if (i != myEntryTimes.end()) {
137 3 : write("leave", SIMTIME, veh, veh.getSpeed());
138 : myEntryTimes.erase(i);
139 : }
140 : return false;
141 : }
142 :
143 :
144 : void
145 954 : MSInstantInductLoop::writeXMLDetectorProlog(OutputDevice& dev) const {
146 1908 : dev.writeXMLHeader("instantE1", "instant_e1_file.xsd");
147 954 : }
148 :
149 :
150 : /****************************************************************************/
|