1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2011-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file    MSInstantInductLoop.cpp
11 /// @author  Daniel Krajzewicz
12 /// @author  Jakob Erdmann
13 /// @author  Michael Behrisch
14 /// @date    2011-09.08
15 /// @version $Id$
16 ///
17 // An instantaneous induction loop
18 /****************************************************************************/
19 
20 
21 // ===========================================================================
22 // included modules
23 // ===========================================================================
24 #include <config.h>
25 
26 #include "MSInstantInductLoop.h"
27 #include <cassert>
28 #include <numeric>
29 #include <utility>
30 #include <utils/common/WrappingCommand.h>
31 #include <utils/common/ToString.h>
32 #include <microsim/MSEventControl.h>
33 #include <microsim/MSLane.h>
34 #include <microsim/MSVehicle.h>
35 #include <microsim/MSNet.h>
36 #include <utils/common/MsgHandler.h>
37 #include <utils/common/UtilExceptions.h>
38 #include <utils/common/StringUtils.h>
39 #include <utils/iodevices/OutputDevice.h>
40 
41 
42 // ===========================================================================
43 // method definitions
44 // ===========================================================================
MSInstantInductLoop(const std::string & id,OutputDevice & od,MSLane * const lane,double positionInMeters,const std::string & vTypes)45 MSInstantInductLoop::MSInstantInductLoop(const std::string& id,
46         OutputDevice& od, MSLane* const lane, double positionInMeters,
47         const std::string& vTypes) :
48     MSMoveReminder(id, lane),
49     MSDetectorFileOutput(id, vTypes),
50     myOutputDevice(od),
51     myPosition(positionInMeters), myLastExitTime(-1) {
52     assert(myPosition >= 0 && myPosition <= myLane->getLength());
53     writeXMLDetectorProlog(od);
54 }
55 
56 
~MSInstantInductLoop()57 MSInstantInductLoop::~MSInstantInductLoop() {
58 }
59 
60 
61 bool
notifyMove(SUMOTrafficObject & veh,double oldPos,double newPos,double newSpeed)62 MSInstantInductLoop::notifyMove(SUMOTrafficObject& veh, double oldPos,
63                                 double newPos, double newSpeed) {
64     if (!vehicleApplies(veh)) {
65         return false;
66     }
67     if (newPos < myPosition) {
68         // detector not reached yet
69         return true;
70     }
71 
72     const double oldSpeed = veh.getPreviousSpeed();
73     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
74 
75     if (newPos >= myPosition && oldPos < myPosition/* && static_cast<MSVehicle&>(veh).getLane() == myLane*/) {
76         const double timeBeforeEnter = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
77         const double entryTime = SIMTIME - TS + timeBeforeEnter;
78         enterSpeed = MSCFModel::speedAfterTime(timeBeforeEnter, oldSpeed, newPos - oldPos);
79         if (myLastExitTime >= 0) {
80             write("enter", entryTime, veh, enterSpeed, "gap", entryTime - myLastExitTime);
81         } else {
82             write("enter", entryTime, veh, enterSpeed);
83         }
84         myEntryTimes[&veh] = entryTime;
85     }
86     const double newBackPos = newPos - veh.getVehicleType().getLength();
87     const double oldBackPos = oldPos - veh.getVehicleType().getLength();
88     if (newBackPos > myPosition) {
89         std::map<SUMOTrafficObject*, double>::iterator i = myEntryTimes.find(&veh);
90         if (i != myEntryTimes.end()) {
91             // vehicle passed the detector
92             const double timeBeforeLeave = MSCFModel::passingTime(oldBackPos, myPosition, newBackPos, oldSpeed, newSpeed);
93             const double leaveTime = SIMTIME - TS + timeBeforeLeave;
94             write("leave", leaveTime, veh, newSpeed, "occupancy", leaveTime - (*i).second);
95             myEntryTimes.erase(i);
96             myLastExitTime = leaveTime;
97         }
98         return false;
99     }
100     // vehicle stays on the detector
101     write("stay", SIMTIME, veh, newSpeed);
102     return true;
103 }
104 
105 
106 void
write(const char * state,double t,SUMOTrafficObject & veh,double speed,const char * add,double addValue)107 MSInstantInductLoop::write(const char* state, double t, SUMOTrafficObject& veh, double speed, const char* add, double addValue) {
108     myOutputDevice.openTag("instantOut").writeAttr(
109         "id", getID()).writeAttr("time", toString(t)).writeAttr("state", state).writeAttr(
110             "vehID", veh.getID()).writeAttr("speed", toString(speed)).writeAttr(
111                 "length", toString(veh.getVehicleType().getLength())).writeAttr(
112                     "type", veh.getVehicleType().getID());
113     if (add != nullptr) {
114         myOutputDevice.writeAttr(add, toString(addValue));
115     }
116     myOutputDevice.closeTag();
117 }
118 
119 
120 bool
notifyLeave(SUMOTrafficObject & veh,double,MSMoveReminder::Notification reason,const MSLane *)121 MSInstantInductLoop::notifyLeave(SUMOTrafficObject& veh, double /* lastPos */, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
122     if (reason == MSMoveReminder::NOTIFICATION_JUNCTION) {
123         // vehicle might have jumped over detector at the end of the lane. we need
124         // one more notifyMove to register it
125         return true;
126     }
127     std::map<SUMOTrafficObject*, double>::iterator i = myEntryTimes.find(&veh);
128     if (i != myEntryTimes.end()) {
129         write("leave", SIMTIME, veh, veh.getSpeed());
130         myEntryTimes.erase(i);
131     }
132     return false;
133 }
134 
135 
136 void
writeXMLDetectorProlog(OutputDevice & dev) const137 MSInstantInductLoop::writeXMLDetectorProlog(OutputDevice& dev) const {
138     dev.writeXMLHeader("instantE1", "instant_e1_file.xsd");
139 }
140 
141 
142 /****************************************************************************/
143