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