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 
const double myPosition
Detector&#39;s position on lane [m].
Definition: MSInductLoop.h:339
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:256
void writeXMLOutput(OutputDevice &dev, SUMOTime startTime, SUMOTime stopTime)
Writes collected values into the given stream.
bool vehicleApplies(const SUMOTrafficObject &veh) const
Checks whether the detector measures vehicles of the given type.
long long int SUMOTime
Definition: SUMOTime.h:35
virtual void leaveDetectorByMove(SUMOTrafficObject &veh, double leaveTimestep)
Processes a vehicle that leaves the detector.
virtual const MSVehicleType & getVehicleType() const =0
Returns the vehicle&#39;s type.
virtual const std::string & getID() const =0
Get the vehicle&#39;s ID.
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.
The vehicle arrived at a junction.
virtual void leaveDetectorByLaneChange(SUMOTrafficObject &veh, double lastPos)
Removes a vehicle from the detector&#39;s map myVehiclesOnDet.
double myLastOccupancy
Occupancy by the last vehicle detected.
Definition: MSInductLoop.h:345
MSLane *const myLane
Lane on which the reminder works.
std::vector< std::string > getCurrentVehicleIDs() const
Returns the ids of vehicles that have passed the detector.
virtual void reset()
Resets all generated values to allow computation of next interval.
static double speedSum(double sumSoFar, const MSInductLoop::VehicleData &data)
Adds up VehicleData::speedM.
Definition: MSInductLoop.h:326
Notification
Definition of a vehicle state.
weights: time range begin
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:168
T MAX2(T a, T b)
Definition: StdDefs.h:80
SUMOTime DELTA_T
Definition: SUMOTime.cpp:35
double getCurrentLength() const
Returns the length of the vehicle on the detector.
const std::string & getID() const
Returns the id.
Definition: Named.h:77
#define TS
Definition: SUMOTime.h:44
bool notifyMove(SUMOTrafficObject &veh, double oldPos, double newPos, double newSpeed)
Checks whether the vehicle shall be counted and/or shall still touch this MSMoveReminder.
VehicleMap myVehiclesOnDet
Data for vehicles that have entered the detector (vehicle -> enter time)
Definition: MSInductLoop.h:366
double speedM
Speed of the vehicle in [m/s].
Definition: MSInductLoop.h:271
VehicleDataCont myLastVehicleDataCont
Data of vehicles that have completely passed the detector in the last time interval.
Definition: MSInductLoop.h:358
#define SIMTIME
Definition: SUMOTime.h:64
VehicleDataCont myVehicleDataCont
Data of vehicles that have completely passed the detector.
Definition: MSInductLoop.h:355
virtual double getBackPositionOnLane(const MSLane *lane) const =0
Get the vehicle&#39;s back position along the given lane.
The vehicle changes lanes (micro only)
void writeXMLDetectorProlog(OutputDevice &dev) const
Opens the XML-output using "detector" as root element.
~MSInductLoop()
Destructor.
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.
double getCurrentSpeed() const
Returns the speed of the vehicle on the detector.
#define STEPS2TIME(x)
Definition: SUMOTime.h:57
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:284
T MIN2(T a, T b)
Definition: StdDefs.h:74
Something on a lane to be noticed about vehicle movement.
static std::string escapeXML(const std::string &orig, const bool maskDoubleHyphen=false)
Replaces the standard escapes by their XML entities.
bool notifyEnter(SUMOTrafficObject &veh, Notification reason, const MSLane *enteredLane=0)
Checks whether the reminder is activated by a vehicle entering the lane.
double getTimeSinceLastDetection() const
Returns the time since the last vehicle left the detector.
virtual double getPreviousSpeed() const =0
Returns the vehicle&#39;s previous speed.
MSInductLoop(const std::string &id, MSLane *const lane, double positionInMeters, const std::string &vTypes)
Constructor.
int myEnteredVehicleNumber
The number of entered vehicles.
Definition: MSInductLoop.h:348
virtual void enterDetectorByMove(SUMOTrafficObject &veh, double entryTimestep)
Introduces a vehicle to the detector&#39;s map myVehiclesOnDet.
#define HAS_NOT_LEFT_DETECTOR
int getCurrentPassedNumber() const
Returns the number of vehicles that have passed the detector.
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
The vehicle starts or ends parking.
The vehicle has departed (was inserted into the network)
Struct to store the data of the counted vehicle internally.
Definition: MSInductLoop.h:248
Representation of a vehicle or person.
weights: time range end
const std::string & getID() const
Returns the name of the vehicle type.
Definition: MSVehicleType.h:94
double getLength() const
Get vehicle&#39;s length [m].
an aggreagated-output interval
virtual double getPositionOnLane() const =0
Get the vehicle&#39;s position along the lane.
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:64
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
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...
double getCurrentOccupancy() const
Returns the current occupancy.
double myLastLeaveTime
Leave-time of the last vehicle detected [s].
Definition: MSInductLoop.h:342
virtual double getSpeed() const =0
Returns the vehicle&#39;s current speed.
Representation of a lane in the micro simulation.
Definition: MSLane.h:83
static double lengthSum(double sumSoFar, const MSInductLoop::VehicleData &data)
Adds up VehicleData::lengthM.
Definition: MSInductLoop.h:331
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
Base of value-generating classes (detectors)
The vehicle is being teleported.