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-2018 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(SUMOVehicle& 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  if (oldBackPos <= myPosition) {
113  const double timeBeforeLeave = MSCFModel::passingTime(oldBackPos, myPosition, newBackPos, oldSpeed, newSpeed);
114  const double leaveTime = SIMTIME + timeBeforeLeave;
115  leaveDetectorByMove(veh, leaveTime);
116  } else {
117  // vehicle is already beyond the detector...
118  // This can happen even if it is still registered in myVehiclesOnDet, e.g., after teleport.
119  // XXX: would we need to call leaveDetectorByMove(veh, leaveTime) as it was done before
120  // I inserted this if-else differentiation? (Leo) It seems that such a call only resets
121  // the last leave Time, which seems inadequate to do for such a situation (though it actually
122  // appears in test output/e1/one_vehicle/lane_change). Moreover, if the vehicle was
123  // not removed, this call would tidy up.
124  // XXX: Indeed, we need to tidy up, e.g., in case of teleport insertion behind detector
125  // XXX: As a quickfix we just remove it. (should be discussed! Leo) Refs. #2579
126 
127  myVehiclesOnDet.erase(&veh);
128  }
129  return false;
130  }
131  // vehicle stays on the detector
132  return true;
133 }
134 
135 
136 bool
137 MSInductLoop::notifyLeave(SUMOVehicle& veh, double lastPos, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
139  leaveDetectorByLaneChange(veh, lastPos);
140  return false;
141  }
142  return true;
143 }
144 
145 
146 double
148  std::vector<VehicleData> d = collectVehiclesOnDet(MSNet::getInstance()->getCurrentTimeStep() - DELTA_T);
149  return d.size() != 0
150  ? accumulate(d.begin(), d.end(), (double) 0.0, speedSum) / (double) d.size()
151  : -1;
152 }
153 
154 
155 double
157  std::vector<VehicleData> d = collectVehiclesOnDet(MSNet::getInstance()->getCurrentTimeStep() - DELTA_T);
158  return d.size() != 0
159  ? accumulate(d.begin(), d.end(), (double) 0.0, lengthSum) / (double) d.size()
160  : -1;
161 }
162 
163 
164 double
167  std::vector<VehicleData> d = collectVehiclesOnDet(tbeg);
168  if (d.size() == 0) {
169  return -1;
170  }
171  double occupancy = 0;
172  double csecond = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep());
173  for (std::vector< VehicleData >::const_iterator i = d.begin(); i != d.end(); ++i) {
174  const double leaveTime = (*i).leaveTimeM == HAS_NOT_LEFT_DETECTOR ? csecond : (*i).leaveTimeM;
175  const double timeOnDetDuringInterval = leaveTime - MAX2(STEPS2TIME(tbeg), (*i).entryTimeM);
176  occupancy += MIN2(timeOnDetDuringInterval, TS);
177  }
178  return occupancy / TS * (double) 100.;
179 }
180 
181 
182 int
184  std::vector<VehicleData> d = collectVehiclesOnDet(MSNet::getInstance()->getCurrentTimeStep() - DELTA_T);
185  return (int) d.size();
186 }
187 
188 
189 std::vector<std::string>
191  std::vector<VehicleData> d = collectVehiclesOnDet(MSNet::getInstance()->getCurrentTimeStep() - DELTA_T);
192  std::vector<std::string> ret;
193  for (std::vector<VehicleData>::iterator i = d.begin(); i != d.end(); ++i) {
194  ret.push_back((*i).idM);
195  }
196  return ret;
197 }
198 
199 
200 double
202  if (myVehiclesOnDet.size() != 0) {
203  // detector is occupied
204  return 0;
205  }
206  return SIMTIME - myLastLeaveTime;
207 }
208 
209 
210 void
212  dev.writeXMLHeader("detector", "det_e1_file.xsd");
213 }
214 
215 
216 void
218  SUMOTime startTime, SUMOTime stopTime) {
219  const double t(STEPS2TIME(stopTime - startTime));
220  const double flow = ((double)myVehicleDataCont.size() / t) * (double) 3600.0;
221  double occupancy = 0.;
222  double speedSum = 0.;
223  double lengthSum = 0.;
224  for (std::deque< VehicleData >::const_iterator i = myVehicleDataCont.begin(); i != myVehicleDataCont.end(); ++i) {
225  const double timeOnDetDuringInterval = i->leaveTimeM - MAX2(STEPS2TIME(startTime), i->entryTimeM);
226  occupancy += MIN2(timeOnDetDuringInterval, t);
227  speedSum += i->speedM;
228  lengthSum += i->lengthM;
229  }
230  for (std::map< SUMOVehicle*, double >::const_iterator i = myVehiclesOnDet.begin(); i != myVehiclesOnDet.end(); ++i) {
231  occupancy += STEPS2TIME(stopTime) - MAX2(STEPS2TIME(startTime), i->second);
232  }
233  occupancy = occupancy / t * (double) 100.;
234  const double meanSpeed = myVehicleDataCont.size() != 0 ? speedSum / (double)myVehicleDataCont.size() : -1;
235  const double meanLength = myVehicleDataCont.size() != 0 ? lengthSum / (double)myVehicleDataCont.size() : -1;
238  dev.writeAttr("flow", flow).writeAttr("occupancy", occupancy).writeAttr("speed", meanSpeed);
239  dev.writeAttr("length", meanLength).writeAttr("nVehEntered", myEnteredVehicleNumber).closeTag();
240  reset();
241 }
242 
243 
244 void
246  double entryTimestep) {
247 // // Debug (Leo)
248 // std::cout << "enterDetectorByMove(), detector = '"<< myID <<"', veh = '" << veh.getID() << "'\n";
249 
250  myVehiclesOnDet.insert(std::make_pair(&veh, entryTimestep));
252 }
253 
254 
255 void
257  double leaveTimestep) {
258 
259 // // Debug (Leo)
260 // std::cout << "leaveDetectorByMove(), detector = '"<< myID <<"', veh = '" << veh.getID() << "'\n";
261 
262  VehicleMap::iterator it = myVehiclesOnDet.find(&veh);
263  if (it != myVehiclesOnDet.end()) {
264  double entryTimestep = it->second;
265  myVehiclesOnDet.erase(it);
266  assert(entryTimestep < leaveTimestep);
267  myVehicleDataCont.push_back(VehicleData(veh.getID(), veh.getVehicleType().getLength(), entryTimestep, leaveTimestep, veh.getVehicleType().getID()));
268  myLastOccupancy = leaveTimestep - entryTimestep;
269  }
270  // XXX: why is this outside the conditional block? (Leo)
271  myLastLeaveTime = leaveTimestep;
272 }
273 
274 
275 void
277 
278 // // Debug (Leo)
279 // std::cout << "leaveDetectorByLaneChange(), detector = '"<< myID <<"', veh = '" << veh.getID() << "'\n";
280 
281  // Discard entry data
282  myVehiclesOnDet.erase(&veh);
283 }
284 
285 
286 std::vector<MSInductLoop::VehicleData>
287 MSInductLoop::collectVehiclesOnDet(SUMOTime tMS, bool leaveTime) const {
288  double t = STEPS2TIME(tMS);
289  std::vector<VehicleData> ret;
290  for (VehicleDataCont::const_iterator i = myVehicleDataCont.begin(); i != myVehicleDataCont.end(); ++i) {
291  if ((*i).entryTimeM >= t || (leaveTime && (*i).leaveTimeM >= t)) {
292  ret.push_back(*i);
293  }
294  }
295  for (VehicleDataCont::const_iterator i = myLastVehicleDataCont.begin(); i != myLastVehicleDataCont.end(); ++i) {
296  if ((*i).entryTimeM >= t || (leaveTime && (*i).leaveTimeM >= t)) {
297  ret.push_back(*i);
298  }
299  }
300  for (VehicleMap::const_iterator i = myVehiclesOnDet.begin(); i != myVehiclesOnDet.end(); ++i) {
301  SUMOVehicle* v = (*i).first;
303  d.speedM = v->getSpeed();
304  ret.push_back(d);
305  }
306  return ret;
307 }
308 
309 
310 /****************************************************************************/
311 
const double myPosition
Detector&#39;s position on lane [m].
Definition: MSInductLoop.h:335
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.
long long int SUMOTime
Definition: SUMOTime.h:36
bool vehicleApplies(const SUMOVehicle &veh) const
Checks whether the detector measures vehicles of the given type.
The vehicle arrived at a junction.
double myLastOccupancy
Occupancy by the last vehicle detected.
Definition: MSInductLoop.h:341
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 leaveDetectorByLaneChange(SUMOVehicle &veh, double lastPos)
Removes a vehicle from the detector&#39;s map myVehiclesOnDet.
virtual void reset()
Resets all generated values to allow computation of next interval.
bool notifyLeave(SUMOVehicle &veh, double lastPos, MSMoveReminder::Notification reason, const MSLane *enteredLane=0)
Dismisses the vehicle if it is on the detector due to a lane change.
static double speedSum(double sumSoFar, const MSInductLoop::VehicleData &data)
Adds up VehicleData::speedM.
Definition: MSInductLoop.h:322
virtual void leaveDetectorByMove(SUMOVehicle &veh, double leaveTimestep)
Processes a vehicle that leaves the detector.
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:165
T MAX2(T a, T b)
Definition: StdDefs.h:76
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:78
#define TS
Definition: SUMOTime.h:45
VehicleMap myVehiclesOnDet
Data for vehicles that have entered the detector (vehicle -> enter time)
Definition: MSInductLoop.h:362
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:354
#define SIMTIME
Definition: SUMOTime.h:65
VehicleDataCont myVehicleDataCont
Data of vehicles that have completely passed the detector.
Definition: MSInductLoop.h:351
The vehicle changes lanes (micro only)
void writeXMLDetectorProlog(OutputDevice &dev) const
Opens the XML-output using "detector" as root element.
Representation of a vehicle.
Definition: SUMOVehicle.h:60
~MSInductLoop()
Destructor.
virtual void enterDetectorByMove(SUMOVehicle &veh, double entryTimestep)
Introduces a vehicle to the detector&#39;s map myVehiclesOnDet.
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:58
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:263
T MIN2(T a, T b)
Definition: StdDefs.h:70
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.
double getTimeSinceLastDetection() const
Returns the time since the last vehicle left the detector.
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:344
#define HAS_NOT_LEFT_DETECTOR
bool notifyEnter(SUMOVehicle &veh, Notification reason, const MSLane *enteredLane=0)
Checks whether the reminder is activated by a vehicle entering the lane.
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
virtual double getBackPositionOnLane(const MSLane *lane) const =0
Get the vehicle&#39;s back position along the given lane.
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
virtual double getPositionOnLane() const =0
Get the vehicle&#39;s position along the lane.
weights: time range end
const std::string & getID() const
Returns the name of the vehicle type.
Definition: MSVehicleType.h:94
bool notifyMove(SUMOVehicle &veh, double oldPos, double newPos, double newSpeed)
Checks whether the vehicle shall be counted and/or shall still touch this MSMoveReminder.
double getLength() const
Get vehicle&#39;s length [m].
an aggreagated-output interval
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.
static bool gSemiImplicitEulerUpdate
Definition: MSGlobals.h:56
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:338
virtual double getSpeed() const =0
Returns the vehicle&#39;s current speed.
Representation of a lane in the micro simulation.
Definition: MSLane.h:78
static double lengthSum(double sumSoFar, const MSInductLoop::VehicleData &data)
Adds up VehicleData::lengthM.
Definition: MSInductLoop.h:327
virtual double getPreviousSpeed() const =0
Returns the vehicle&#39;s previous speed.
virtual const std::string & getID() const =0
Get the vehicle&#39;s ID.
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
Base of value-generating classes (detectors)
The vehicle is being teleported.
virtual const MSVehicleType & getVehicleType() const =0
Returns the vehicle&#39;s type.