Eclipse SUMO - Simulation of Urban MObility
MSInductLoop.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-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 /****************************************************************************/
20 // An unextended detector measuring at a fixed position on a fixed lane.
21 /****************************************************************************/
22 
23 
24 // ===========================================================================
25 // included modules
26 // ===========================================================================
27 #include <config.h>
28 
29 #include "MSInductLoop.h"
30 #include <cassert>
31 #include <numeric>
32 #include <utility>
34 #include <utils/common/ToString.h>
36 #include <microsim/MSLane.h>
37 #include <microsim/MSVehicle.h>
38 #include <microsim/MSNet.h>
43 
44 #define HAS_NOT_LEFT_DETECTOR -1
45 
46 // ===========================================================================
47 // method definitions
48 // ===========================================================================
49 MSInductLoop::MSInductLoop(const std::string& id, MSLane* const lane,
50  double positionInMeters,
51  const std::string& vTypes) :
52  MSMoveReminder(id, lane),
53  MSDetectorFileOutput(id, vTypes),
54  myPosition(positionInMeters),
55  myLastLeaveTime(SIMTIME),
56  myVehicleDataCont(),
57  myVehiclesOnDet() {
58  assert(myPosition >= 0 && myPosition <= myLane->getLength());
59  reset();
60 }
61 
62 
64 }
65 
66 
67 void
71  myVehicleDataCont.clear();
72 }
73 
74 
75 bool
76 MSInductLoop::notifyEnter(SUMOTrafficObject& veh, Notification reason, const MSLane* /* enteredLane */) {
77  if (!vehicleApplies(veh)) {
78  return false;
79  }
80  if (reason == NOTIFICATION_DEPARTED ||
81  reason == NOTIFICATION_TELEPORT ||
82  reason == NOTIFICATION_PARKING ||
83  reason == NOTIFICATION_LANE_CHANGE) {
85  myVehiclesOnDet.insert(std::make_pair(&veh, SIMTIME));
87  }
88  }
89  return true;
90 }
91 
92 
93 bool
95  double newPos, double newSpeed) {
96  if (newPos < myPosition) {
97  // detector not reached yet
98  return true;
99  }
100  const double oldSpeed = veh.getPreviousSpeed();
101  if (newPos >= myPosition && oldPos < myPosition) {
102  // entered the detector by move
103  const double timeBeforeEnter = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
104  double entryTime = SIMTIME + timeBeforeEnter;
105  enterDetectorByMove(veh, entryTime);
106  }
107  double oldBackPos = oldPos - veh.getVehicleType().getLength();
108  double newBackPos = newPos - veh.getVehicleType().getLength();
109  if (newBackPos > myPosition) {
110  // vehicle passed the detector (it may have changed onto this lane somewhere past the detector)
111  // assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed > 0 || myVehiclesOnDet.find(&veh) == myVehiclesOnDet.end());
112  // assertion is invalid in case of teleportation
113  if (oldBackPos <= myPosition) {
114  const double timeBeforeLeave = MSCFModel::passingTime(oldBackPos, myPosition, newBackPos, oldSpeed, newSpeed);
115  const double leaveTime = SIMTIME + timeBeforeLeave;
116  leaveDetectorByMove(veh, leaveTime);
117  } else {
118  // vehicle is already beyond the detector...
119  // This can happen even if it is still registered in myVehiclesOnDet, e.g., after teleport.
120  // XXX: would we need to call leaveDetectorByMove(veh, leaveTime) as it was done before
121  // I inserted this if-else differentiation? (Leo) It seems that such a call only resets
122  // the last leave Time, which seems inadequate to do for such a situation (though it actually
123  // appears in test output/e1/one_vehicle/lane_change). Moreover, if the vehicle was
124  // not removed, this call would tidy up.
125  // XXX: Indeed, we need to tidy up, e.g., in case of teleport insertion behind detector
126  // XXX: As a quickfix we just remove it. (should be discussed! Leo) Refs. #2579
127 
128  myVehiclesOnDet.erase(&veh);
129  }
130  return false;
131  }
132  // vehicle stays on the detector
133  return true;
134 }
135 
136 
137 bool
138 MSInductLoop::notifyLeave(SUMOTrafficObject& veh, double lastPos, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
140  leaveDetectorByLaneChange(veh, lastPos);
141  return false;
142  }
143  return true;
144 }
145 
146 
147 double
149  std::vector<VehicleData> d = collectVehiclesOnDet(MSNet::getInstance()->getCurrentTimeStep() - DELTA_T);
150  return d.size() != 0
151  ? std::accumulate(d.begin(), d.end(), (double) 0.0, speedSum) / (double) d.size()
152  : -1;
153 }
154 
155 
156 double
158  std::vector<VehicleData> d = collectVehiclesOnDet(MSNet::getInstance()->getCurrentTimeStep() - DELTA_T);
159  return d.size() != 0
160  ? std::accumulate(d.begin(), d.end(), (double) 0.0, lengthSum) / (double) d.size()
161  : -1;
162 }
163 
164 
165 double
168  std::vector<VehicleData> d = collectVehiclesOnDet(tbeg);
169  if (d.size() == 0) {
170  return -1;
171  }
172  double occupancy = 0;
173  double csecond = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep());
174  for (std::vector< VehicleData >::const_iterator i = d.begin(); i != d.end(); ++i) {
175  const double leaveTime = (*i).leaveTimeM == HAS_NOT_LEFT_DETECTOR ? csecond : (*i).leaveTimeM;
176  const double timeOnDetDuringInterval = leaveTime - MAX2(STEPS2TIME(tbeg), (*i).entryTimeM);
177  occupancy += MIN2(timeOnDetDuringInterval, TS);
178  }
179  return occupancy / TS * (double) 100.;
180 }
181 
182 
183 int
185  std::vector<VehicleData> d = collectVehiclesOnDet(MSNet::getInstance()->getCurrentTimeStep() - DELTA_T);
186  return (int) d.size();
187 }
188 
189 
190 std::vector<std::string>
192  std::vector<VehicleData> d = collectVehiclesOnDet(MSNet::getInstance()->getCurrentTimeStep() - DELTA_T);
193  std::vector<std::string> ret;
194  for (std::vector<VehicleData>::iterator i = d.begin(); i != d.end(); ++i) {
195  ret.push_back((*i).idM);
196  }
197  return ret;
198 }
199 
200 
201 double
203  if (myVehiclesOnDet.size() != 0) {
204  // detector is occupied
205  return 0;
206  }
207  return SIMTIME - myLastLeaveTime;
208 }
209 
210 
211 void
213  dev.writeXMLHeader("detector", "det_e1_file.xsd");
214 }
215 
216 
217 void
219  SUMOTime startTime, SUMOTime stopTime) {
220  const double t(STEPS2TIME(stopTime - startTime));
221  const double flow = ((double)myVehicleDataCont.size() / t) * (double) 3600.0;
222  double occupancy = 0.;
223  double speedSum = 0.;
224  double lengthSum = 0.;
225  // to approximate the space mean speed
226  double inverseSpeedSum = 0.;
227  for (std::deque< VehicleData >::const_iterator i = myVehicleDataCont.begin(); i != myVehicleDataCont.end(); ++i) {
228  const double timeOnDetDuringInterval = i->leaveTimeM - MAX2(STEPS2TIME(startTime), i->entryTimeM);
229  occupancy += MIN2(timeOnDetDuringInterval, t);
230  speedSum += i->speedM;
231  assert(i->speedM > 0);
232  inverseSpeedSum += 1. / i->speedM;
233  lengthSum += i->lengthM;
234  }
235  for (std::map< SUMOTrafficObject*, double >::const_iterator i = myVehiclesOnDet.begin(); i != myVehiclesOnDet.end(); ++i) {
236  occupancy += STEPS2TIME(stopTime) - MAX2(STEPS2TIME(startTime), i->second);
237  }
238  occupancy = occupancy / t * (double) 100.;
239  const double meanSpeed = myVehicleDataCont.size() != 0 ? speedSum / (double)myVehicleDataCont.size() : -1;
240  const double harmonicMeanSpeed = myVehicleDataCont.size() != 0 ? (double)myVehicleDataCont.size() / inverseSpeedSum : -1;
241  const double meanLength = myVehicleDataCont.size() != 0 ? lengthSum / (double)myVehicleDataCont.size() : -1;
244  dev.writeAttr("flow", flow).writeAttr("occupancy", occupancy).writeAttr("speed", meanSpeed).writeAttr("harmonicMeanSpeed", harmonicMeanSpeed);
245  dev.writeAttr("length", meanLength).writeAttr("nVehEntered", myEnteredVehicleNumber).closeTag();
246  reset();
247 }
248 
249 
250 void
252  double entryTimestep) {
253 // // Debug (Leo)
254 // std::cout << "enterDetectorByMove(), detector = '"<< myID <<"', veh = '" << veh.getID() << "'\n";
255 
256  myVehiclesOnDet.insert(std::make_pair(&veh, entryTimestep));
258 }
259 
260 
261 void
263  double leaveTimestep) {
264 
265 // // Debug (Leo)
266 // std::cout << "leaveDetectorByMove(), detector = '"<< myID <<"', veh = '" << veh.getID() << "'\n";
267 
268  VehicleMap::iterator it = myVehiclesOnDet.find(&veh);
269  if (it != myVehiclesOnDet.end()) {
270  double entryTimestep = it->second;
271  myVehiclesOnDet.erase(it);
272  assert(entryTimestep < leaveTimestep);
273  myVehicleDataCont.push_back(VehicleData(veh.getID(), veh.getVehicleType().getLength(), entryTimestep, leaveTimestep, veh.getVehicleType().getID()));
274  myLastOccupancy = leaveTimestep - entryTimestep;
275  }
276  // XXX: why is this outside the conditional block? (Leo)
277  myLastLeaveTime = leaveTimestep;
278 }
279 
280 
281 void
283 
284 // // Debug (Leo)
285 // std::cout << "leaveDetectorByLaneChange(), detector = '"<< myID <<"', veh = '" << veh.getID() << "'\n";
286 
287  // Discard entry data
288  myVehiclesOnDet.erase(&veh);
289 }
290 
291 
292 std::vector<MSInductLoop::VehicleData>
293 MSInductLoop::collectVehiclesOnDet(SUMOTime tMS, bool leaveTime) const {
294  double t = STEPS2TIME(tMS);
295  std::vector<VehicleData> ret;
296  for (VehicleDataCont::const_iterator i = myVehicleDataCont.begin(); i != myVehicleDataCont.end(); ++i) {
297  if ((*i).entryTimeM >= t || (leaveTime && (*i).leaveTimeM >= t)) {
298  ret.push_back(*i);
299  }
300  }
301  for (VehicleDataCont::const_iterator i = myLastVehicleDataCont.begin(); i != myLastVehicleDataCont.end(); ++i) {
302  if ((*i).entryTimeM >= t || (leaveTime && (*i).leaveTimeM >= t)) {
303  ret.push_back(*i);
304  }
305  }
306  for (VehicleMap::const_iterator i = myVehiclesOnDet.begin(); i != myVehiclesOnDet.end(); ++i) {
307  SUMOTrafficObject* v = (*i).first;
309  d.speedM = v->getSpeed();
310  ret.push_back(d);
311  }
312  return ret;
313 }
314 
315 
316 /****************************************************************************/
317 
MSMoveReminder::NOTIFICATION_LANE_CHANGE
The vehicle changes lanes (micro only)
Definition: MSMoveReminder.h:97
SUMOTrafficObject
Representation of a vehicle or person.
Definition: SUMOTrafficObject.h:48
ToString.h
MSVehicleType::getID
const std::string & getID() const
Returns the name of the vehicle type.
Definition: MSVehicleType.h:94
MIN2
T MIN2(T a, T b)
Definition: StdDefs.h:74
MSNet.h
MSDetectorFileOutput
Base of value-generating classes (detectors)
Definition: MSDetectorFileOutput.h:64
MSInductLoop::myLastLeaveTime
double myLastLeaveTime
Leave-time of the last vehicle detected [s].
Definition: MSInductLoop.h:342
MSLane
Representation of a lane in the micro simulation.
Definition: MSLane.h:83
MSInductLoop::getCurrentLength
double getCurrentLength() const
Returns the length of the vehicle on the detector.
Definition: MSInductLoop.cpp:157
MSInductLoop::VehicleData
Struct to store the data of the counted vehicle internally.
Definition: MSInductLoop.h:248
MSInductLoop::enterDetectorByMove
virtual void enterDetectorByMove(SUMOTrafficObject &veh, double entryTimestep)
Introduces a vehicle to the detector's map myVehiclesOnDet.
Definition: MSInductLoop.cpp:251
MSInductLoop::lengthSum
static double lengthSum(double sumSoFar, const MSInductLoop::VehicleData &data)
Adds up VehicleData::lengthM.
Definition: MSInductLoop.h:331
OutputDevice
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:64
DELTA_T
SUMOTime DELTA_T
Definition: SUMOTime.cpp:35
SUMOTrafficObject::getVehicleType
virtual const MSVehicleType & getVehicleType() const =0
Returns the vehicle's type.
SUMOTrafficObject::getID
virtual const std::string & getID() const =0
Get the vehicle's ID.
MsgHandler.h
WrappingCommand.h
SUMOTime
long long int SUMOTime
Definition: SUMOTime.h:35
MSInductLoop::getCurrentSpeed
double getCurrentSpeed() const
Returns the speed of the vehicle on the detector.
Definition: MSInductLoop.cpp:148
SUMO_ATTR_ID
Definition: SUMOXMLDefinitions.h:379
MSInductLoop::notifyEnter
bool notifyEnter(SUMOTrafficObject &veh, Notification reason, const MSLane *enteredLane=0)
Checks whether the reminder is activated by a vehicle entering the lane.
Definition: MSInductLoop.cpp:76
MSInductLoop::getTimeSinceLastDetection
double getTimeSinceLastDetection() const
Returns the time since the last vehicle left the detector.
Definition: MSInductLoop.cpp:202
MSInductLoop::leaveDetectorByLaneChange
virtual void leaveDetectorByLaneChange(SUMOTrafficObject &veh, double lastPos)
Removes a vehicle from the detector's map myVehiclesOnDet.
Definition: MSInductLoop.cpp:282
SUMOTrafficObject::getBackPositionOnLane
virtual double getBackPositionOnLane(const MSLane *lane) const =0
Get the vehicle's back position along the given lane.
MSInductLoop::myLastOccupancy
double myLastOccupancy
Occupancy by the last vehicle detected.
Definition: MSInductLoop.h:345
MSVehicle.h
MSMoveReminder
Something on a lane to be noticed about vehicle movement.
Definition: MSMoveReminder.h:64
OutputDevice::closeTag
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
Definition: OutputDevice.cpp:254
SUMO_ATTR_BEGIN
weights: time range begin
Definition: SUMOXMLDefinitions.h:675
MAX2
T MAX2(T a, T b)
Definition: StdDefs.h:80
MSInductLoop::getCurrentOccupancy
double getCurrentOccupancy() const
Returns the current occupancy.
Definition: MSInductLoop.cpp:166
OutputDevice::writeAttr
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:256
MSInductLoop::VehicleData::speedM
double speedM
Speed of the vehicle in [m/s].
Definition: MSInductLoop.h:271
SIMTIME
#define SIMTIME
Definition: SUMOTime.h:64
MSInductLoop::leaveDetectorByMove
virtual void leaveDetectorByMove(SUMOTrafficObject &veh, double leaveTimestep)
Processes a vehicle that leaves the detector.
Definition: MSInductLoop.cpp:262
TS
#define TS
Definition: SUMOTime.h:44
MSNet::getCurrentTimeStep
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:284
MSInductLoop::myVehiclesOnDet
VehicleMap myVehiclesOnDet
Data for vehicles that have entered the detector (vehicle -> enter time)
Definition: MSInductLoop.h:366
STEPS2TIME
#define STEPS2TIME(x)
Definition: SUMOTime.h:57
StringUtils::escapeXML
static std::string escapeXML(const std::string &orig, const bool maskDoubleHyphen=false)
Replaces the standard escapes by their XML entities.
Definition: StringUtils.cpp:158
OutputDevice.h
MSInductLoop::getCurrentPassedNumber
int getCurrentPassedNumber() const
Returns the number of vehicles that have passed the detector.
Definition: MSInductLoop.cpp:184
UtilExceptions.h
MSInductLoop::speedSum
static double speedSum(double sumSoFar, const MSInductLoop::VehicleData &data)
Adds up VehicleData::speedM.
Definition: MSInductLoop.h:326
MSMoveReminder::NOTIFICATION_DEPARTED
The vehicle has departed (was inserted into the network)
Definition: MSMoveReminder.h:91
MSInductLoop::collectVehiclesOnDet
virtual std::vector< VehicleData > collectVehiclesOnDet(SUMOTime t, bool leaveTime=false) const
Returns vehicle data for vehicles that have been on the detector starting at the given time.
Definition: MSInductLoop.cpp:293
MSInductLoop::getCurrentVehicleIDs
std::vector< std::string > getCurrentVehicleIDs() const
Returns the ids of vehicles that have passed the detector.
Definition: MSInductLoop.cpp:191
MSInductLoop::notifyMove
bool notifyMove(SUMOTrafficObject &veh, double oldPos, double newPos, double newSpeed)
Checks whether the vehicle shall be counted and/or shall still touch this MSMoveReminder.
Definition: MSInductLoop.cpp:94
OutputDevice::openTag
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
Definition: OutputDevice.cpp:240
StringUtils.h
MSMoveReminder::NOTIFICATION_PARKING
The vehicle starts or ends parking.
Definition: MSMoveReminder.h:103
MSNet::getInstance
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:168
SUMOTrafficObject::getPreviousSpeed
virtual double getPreviousSpeed() const =0
Returns the vehicle's previous speed.
MSInductLoop::notifyLeave
bool notifyLeave(SUMOTrafficObject &veh, double lastPos, MSMoveReminder::Notification reason, const MSLane *enteredLane=0)
Dismisses the vehicle if it is on the detector due to a lane change.
Definition: MSInductLoop.cpp:138
MSVehicleType::getLength
double getLength() const
Get vehicle's length [m].
Definition: MSVehicleType.h:110
MSInductLoop::myLastVehicleDataCont
VehicleDataCont myLastVehicleDataCont
Data of vehicles that have completely passed the detector in the last time interval.
Definition: MSInductLoop.h:358
MSDetectorFileOutput::vehicleApplies
bool vehicleApplies(const SUMOTrafficObject &veh) const
Checks whether the detector measures vehicles of the given type.
Definition: MSDetectorFileOutput.h:142
config.h
MSInductLoop::~MSInductLoop
~MSInductLoop()
Destructor.
Definition: MSInductLoop.cpp:63
MSCFModel::passingTime
static double passingTime(const double lastPos, const double passedPos, const double currentPos, const double lastSpeed, const double currentSpeed)
Calculates the time at which the position passedPosition has been passed In case of a ballistic updat...
Definition: MSCFModel.cpp:597
MSInductLoop::myPosition
const double myPosition
Detector's position on lane [m].
Definition: MSInductLoop.h:339
SUMO_ATTR_END
weights: time range end
Definition: SUMOXMLDefinitions.h:677
MSInductLoop::writeXMLOutput
void writeXMLOutput(OutputDevice &dev, SUMOTime startTime, SUMOTime stopTime)
Writes collected values into the given stream.
Definition: MSInductLoop.cpp:218
SUMO_TAG_INTERVAL
an aggreagated-output interval
Definition: SUMOXMLDefinitions.h:160
MSEventControl.h
MSLane.h
OutputDevice::writeXMLHeader
bool writeXMLHeader(const std::string &rootElement, const std::string &schemaFile, std::map< SumoXMLAttr, std::string > attrs=std::map< SumoXMLAttr, std::string >())
Writes an XML header with optional configuration.
Definition: OutputDevice.cpp:228
MSInductLoop.h
SUMOTrafficObject::getPositionOnLane
virtual double getPositionOnLane() const =0
Get the vehicle's position along the lane.
HAS_NOT_LEFT_DETECTOR
#define HAS_NOT_LEFT_DETECTOR
Definition: MSInductLoop.cpp:44
MSInductLoop::MSInductLoop
MSInductLoop(const std::string &id, MSLane *const lane, double positionInMeters, const std::string &vTypes)
Constructor.
Definition: MSInductLoop.cpp:49
MSInductLoop::myVehicleDataCont
VehicleDataCont myVehicleDataCont
Data of vehicles that have completely passed the detector.
Definition: MSInductLoop.h:355
MSInductLoop::myEnteredVehicleNumber
int myEnteredVehicleNumber
The number of entered vehicles.
Definition: MSInductLoop.h:348
Named::getID
const std::string & getID() const
Returns the id.
Definition: Named.h:77
MSMoveReminder::Notification
Notification
Definition of a vehicle state.
Definition: MSMoveReminder.h:89
MSMoveReminder::NOTIFICATION_JUNCTION
The vehicle arrived at a junction.
Definition: MSMoveReminder.h:93
MSInductLoop::reset
virtual void reset()
Resets all generated values to allow computation of next interval.
Definition: MSInductLoop.cpp:68
MSMoveReminder::NOTIFICATION_TELEPORT
The vehicle is being teleported.
Definition: MSMoveReminder.h:101
MSMoveReminder::myLane
MSLane *const myLane
Lane on which the reminder works.
Definition: MSMoveReminder.h:238
SUMOTrafficObject::getSpeed
virtual double getSpeed() const =0
Returns the vehicle's current speed.
MSInductLoop::writeXMLDetectorProlog
void writeXMLDetectorProlog(OutputDevice &dev) const
Opens the XML-output using "detector" as root element.
Definition: MSInductLoop.cpp:212