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-2020 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials are made available under the
5 // terms of the Eclipse Public License 2.0 which is available at
6 // https://www.eclipse.org/legal/epl-2.0/
7 // This Source Code may also be made available under the following Secondary
8 // Licenses when the conditions for such availability set forth in the Eclipse
9 // Public License 2.0 are satisfied: GNU General Public License, version 2
10 // or later which is available at
11 // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 /****************************************************************************/
23 // An unextended detector measuring at a fixed position on a fixed lane.
24 /****************************************************************************/
25 #include <config.h>
26 
27 #include "MSInductLoop.h"
28 #include <cassert>
29 #include <numeric>
30 #include <utility>
32 #include <utils/common/ToString.h>
34 #include <microsim/MSLane.h>
35 #include <microsim/MSVehicle.h>
36 #include <microsim/MSNet.h>
41 
42 #define HAS_NOT_LEFT_DETECTOR -1
43 
44 // ===========================================================================
45 // method definitions
46 // ===========================================================================
47 MSInductLoop::MSInductLoop(const std::string& id, MSLane* const lane,
48  double positionInMeters,
49  const std::string& vTypes,
50  const bool needLocking) :
51  MSMoveReminder(id, lane),
52  MSDetectorFileOutput(id, vTypes),
53  myPosition(positionInMeters),
54  myNeedLock(needLocking || MSGlobals::gNumSimThreads > 1),
55  myLastLeaveTime(SIMTIME),
56  myVehicleDataCont(),
57  myVehiclesOnDet() {
58  assert(myPosition >= 0 && myPosition <= myLane->getLength());
59  reset();
60 }
61 
62 
64 }
65 
66 
67 void
69 #ifdef HAVE_FOX
70  FXConditionalLock lock(myNotificationMutex, myNeedLock);
71 #endif
74  myVehicleDataCont.clear();
75 }
76 
77 
78 bool
79 MSInductLoop::notifyEnter(SUMOTrafficObject& veh, Notification reason, const MSLane* /* enteredLane */) {
80  if (!vehicleApplies(veh)) {
81  return false;
82  }
83  if (reason != NOTIFICATION_JUNCTION) { // the junction case is handled in notifyMove
85  return false;
86  }
87  if (veh.getPositionOnLane() >= myPosition) {
88 #ifdef HAVE_FOX
89  FXConditionalLock lock(myNotificationMutex, myNeedLock);
90 #endif
91  myVehiclesOnDet[&veh] = SIMTIME;
93  }
94  }
95  return true;
96 }
97 
98 
99 bool
101  double newPos, double newSpeed) {
102  if (newPos < myPosition) {
103  // detector not reached yet
104  return true;
105  }
106 #ifdef HAVE_FOX
107  FXConditionalLock lock(myNotificationMutex, myNeedLock);
108 #endif
109  const double oldSpeed = veh.getPreviousSpeed();
110  if (newPos >= myPosition && oldPos < myPosition) {
111  // entered the detector by move
112  const double timeBeforeEnter = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
113  myVehiclesOnDet[&veh] = SIMTIME + timeBeforeEnter;
115  }
116  double oldBackPos = oldPos - veh.getVehicleType().getLength();
117  double newBackPos = newPos - veh.getVehicleType().getLength();
118  if (newBackPos > myPosition) {
119  // vehicle passed the detector (it may have changed onto this lane somewhere past the detector)
120  // assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed > 0 || myVehiclesOnDet.find(&veh) == myVehiclesOnDet.end());
121  // assertion is invalid in case of teleportation
122  if (oldBackPos <= myPosition) {
123  const std::map<SUMOTrafficObject*, double>::iterator it = myVehiclesOnDet.find(&veh);
124  if (it != myVehiclesOnDet.end()) {
125  const double entryTime = it->second;
126  const double leaveTime = SIMTIME + MSCFModel::passingTime(oldBackPos, myPosition, newBackPos, oldSpeed, newSpeed);
127  myVehiclesOnDet.erase(it);
128  assert(entryTime <= leaveTime);
129  myVehicleDataCont.push_back(VehicleData(veh, entryTime, leaveTime, false));
130  myLastLeaveTime = leaveTime;
131  }
132  } else {
133  // vehicle is already beyond the detector...
134  // This can happen even if it is still registered in myVehiclesOnDet, e.g., after teleport.
135  myVehiclesOnDet.erase(&veh);
136  }
137  return false;
138  }
139  // vehicle stays on the detector
140  return true;
141 }
142 
143 
144 bool
145 MSInductLoop::notifyLeave(SUMOTrafficObject& veh, double /* lastPos */, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
147 #ifdef HAVE_FOX
148  FXConditionalLock lock(myNotificationMutex, myNeedLock);
149 #endif
150  const std::map<SUMOTrafficObject*, double>::iterator it = myVehiclesOnDet.find(&veh);
151  if (it != myVehiclesOnDet.end()) {
152  const double entryTime = it->second;
153  const double leaveTime = SIMTIME + TS;
154  myVehiclesOnDet.erase(it);
155  myVehicleDataCont.push_back(VehicleData(veh, entryTime, leaveTime, true));
156  myLastLeaveTime = leaveTime;
157  }
158  return false;
159  }
160  return true;
161 }
162 
163 
164 double
165 MSInductLoop::getSpeed(const int offset) const {
166  const std::vector<VehicleData>& d = collectVehiclesOnDet(SIMSTEP - offset);
167  return d.empty() ? -1. : std::accumulate(d.begin(), d.end(), 0.0, speedSum) / (double) d.size();
168 }
169 
170 
171 double
172 MSInductLoop::getVehicleLength(const int offset) const {
173  const std::vector<VehicleData>& d = collectVehiclesOnDet(SIMSTEP - offset);
174  return d.empty() ? -1. : std::accumulate(d.begin(), d.end(), 0.0, lengthSum) / (double)d.size();
175 }
176 
177 
178 double
180  const SUMOTime tbeg = SIMSTEP - DELTA_T;
181  double occupancy = 0;
182  const double csecond = SIMTIME;
183  for (const VehicleData& i : collectVehiclesOnDet(tbeg, false, false, true)) {
184  const double leaveTime = i.leaveTimeM == HAS_NOT_LEFT_DETECTOR ? csecond : MIN2(i.leaveTimeM, csecond);
185  const double entryTime = MAX2(i.entryTimeM, STEPS2TIME(tbeg));
186  occupancy += MIN2(leaveTime - entryTime, TS);
187  }
188  return occupancy / TS * 100.;
189 }
190 
191 
192 double
193 MSInductLoop::getEnteredNumber(const int offset) const {
194  return (double)collectVehiclesOnDet(SIMSTEP - offset, true, true).size();
195 }
196 
197 
198 std::vector<std::string>
199 MSInductLoop::getVehicleIDs(const int offset) const {
200  std::vector<std::string> ret;
201  for (const VehicleData& i : collectVehiclesOnDet(SIMSTEP - offset, true, true)) {
202  ret.push_back(i.idM);
203  }
204  return ret;
205 }
206 
207 
208 double
210  if (myVehiclesOnDet.size() != 0) {
211  // detector is occupied
212  return 0;
213  }
214  return SIMTIME - myLastLeaveTime;
215 }
216 
217 
218 SUMOTime
220  if (myVehiclesOnDet.size() != 0) {
222  }
223  return TIME2STEPS(myLastLeaveTime);
224 }
225 
226 
227 void
229  dev.writeXMLHeader("detector", "det_e1_file.xsd");
230 }
231 
232 
233 void
235  const double t(STEPS2TIME(stopTime - startTime));
236  double occupancy = 0.;
237  double speedSum = 0.;
238  double lengthSum = 0.;
239  int contrib = 0;
240  // to approximate the space mean speed
241  double inverseSpeedSum = 0.;
242  for (const VehicleData& vData : myVehicleDataCont) {
243  const double timeOnDetDuringInterval = vData.leaveTimeM - MAX2(STEPS2TIME(startTime), vData.entryTimeM);
244  occupancy += MIN2(timeOnDetDuringInterval, t);
245  if (!vData.leftEarlyM) {
246  speedSum += vData.speedM;
247  assert(vData.speedM > 0.);
248  inverseSpeedSum += 1. / vData.speedM;
249  lengthSum += vData.lengthM;
250  contrib++;
251  }
252  }
253  const double flow = (double)contrib / t * 3600.;
254  for (std::map< SUMOTrafficObject*, double >::const_iterator i = myVehiclesOnDet.begin(); i != myVehiclesOnDet.end(); ++i) {
255  occupancy += STEPS2TIME(stopTime) - MAX2(STEPS2TIME(startTime), i->second);
256  }
257  occupancy *= 100. / t;
258  const double meanSpeed = contrib != 0 ? speedSum / (double)contrib : -1;
259  const double harmonicMeanSpeed = contrib != 0 ? (double)contrib / inverseSpeedSum : -1;
260  const double meanLength = contrib != 0 ? lengthSum / (double)contrib : -1;
261  dev.openTag(SUMO_TAG_INTERVAL).writeAttr(SUMO_ATTR_BEGIN, STEPS2TIME(startTime)).writeAttr(SUMO_ATTR_END, STEPS2TIME(stopTime));
262  dev.writeAttr(SUMO_ATTR_ID, StringUtils::escapeXML(getID())).writeAttr("nVehContrib", contrib);
263  dev.writeAttr("flow", flow).writeAttr("occupancy", occupancy).writeAttr("speed", meanSpeed).writeAttr("harmonicMeanSpeed", harmonicMeanSpeed);
264  dev.writeAttr("length", meanLength).writeAttr("nVehEntered", myEnteredVehicleNumber).closeTag();
265  reset();
266 }
267 
268 
269 std::vector<MSInductLoop::VehicleData>
270 MSInductLoop::collectVehiclesOnDet(SUMOTime tMS, bool includeEarly, bool leaveTime, bool forOccupancy) const {
271 #ifdef HAVE_FOX
272  FXConditionalLock lock(myNotificationMutex, myNeedLock);
273 #endif
274  const double t = STEPS2TIME(tMS);
275  std::vector<VehicleData> ret;
276  for (const VehicleData& i : myVehicleDataCont) {
277  if (includeEarly || !i.leftEarlyM) {
278  if (i.entryTimeM >= t || (leaveTime && i.leaveTimeM >= t)) {
279  ret.push_back(i);
280  }
281  }
282  }
283  for (const VehicleData& i : myLastVehicleDataCont) {
284  if (includeEarly || !i.leftEarlyM) {
285  if (i.entryTimeM >= t || (leaveTime && i.leaveTimeM >= t)) {
286  ret.push_back(i);
287  }
288  }
289  }
290  for (const auto& i : myVehiclesOnDet) {
291  if (i.second >= t || leaveTime || forOccupancy) { // no need to check leave time, they are still on the detector
292  SUMOTrafficObject* const v = i.first;
293  VehicleData d(*v, i.second, HAS_NOT_LEFT_DETECTOR, false);
294  d.speedM = v->getSpeed();
295  ret.push_back(d);
296  }
297  }
298  return ret;
299 }
300 
301 
303  double leaveTimestep, const bool leftEarly)
304  : idM(v.getID()), lengthM(v.getVehicleType().getLength()), entryTimeM(entryTimestep), leaveTimeM(leaveTimestep),
305  speedM(v.getVehicleType().getLength() / MAX2(leaveTimestep - entryTimestep, NUMERICAL_EPS)), typeIDM(v.getVehicleType().getID()),
306  leftEarlyM(leftEarly) {}
307 
308 
309 void
312  myLastVehicleDataCont.clear();
313  myVehicleDataCont.clear();
314  myVehiclesOnDet.clear();
315 }
316 
317 /****************************************************************************/
#define HAS_NOT_LEFT_DETECTOR
SUMOTime DELTA_T
Definition: SUMOTime.cpp:37
#define STEPS2TIME(x)
Definition: SUMOTime.h:53
#define SIMSTEP
Definition: SUMOTime.h:59
#define TS
Definition: SUMOTime.h:40
#define SIMTIME
Definition: SUMOTime.h:60
#define TIME2STEPS(x)
Definition: SUMOTime.h:55
long long int SUMOTime
Definition: SUMOTime.h:31
@ SUMO_TAG_INTERVAL
an aggreagated-output interval
@ SUMO_ATTR_BEGIN
weights: time range begin
@ SUMO_ATTR_END
weights: time range end
@ SUMO_ATTR_ID
T MIN2(T a, T b)
Definition: StdDefs.h:73
T MAX2(T a, T b)
Definition: StdDefs.h:79
A scoped lock which only triggers on condition.
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:595
Base of value-generating classes (detectors)
bool vehicleApplies(const SUMOTrafficObject &veh) const
Checks whether the detector measures vehicles of the given type.
static double lengthSum(double sumSoFar, const MSInductLoop::VehicleData &data)
Adds up VehicleData::lengthM.
Definition: MSInductLoop.h:305
double getOccupancy() const
Returns the current occupancy.
int myEnteredVehicleNumber
The number of entered vehicles.
Definition: MSInductLoop.h:322
double getEnteredNumber(const int offset) const
Returns the number of vehicles that have passed the detector.
MSInductLoop(const std::string &id, MSLane *const lane, double positionInMeters, const std::string &vTypes, const bool needLocking)
Constructor.
void writeXMLOutput(OutputDevice &dev, SUMOTime startTime, SUMOTime stopTime)
Writes collected values into the given stream.
static double speedSum(double sumSoFar, const MSInductLoop::VehicleData &data)
Adds up VehicleData::speedM.
Definition: MSInductLoop.h:300
VehicleDataCont myVehicleDataCont
Data of vehicles that have completely passed the detector.
Definition: MSInductLoop.h:328
double getSpeed(const int offset) const
Returns the speed of the vehicle on the detector.
virtual void clearState()
Remove all vehicles before quick-loading state.
std::vector< std::string > getVehicleIDs(const int offset) const
Returns the ids of vehicles that have passed the detector.
double getVehicleLength(const int offset) const
Returns the length of the vehicle on the detector.
virtual void reset()
Resets all generated values to allow computation of next interval.
const double myPosition
Detector's position on lane [m].
Definition: MSInductLoop.h:313
VehicleDataCont myLastVehicleDataCont
Data of vehicles that have completely passed the detector in the last time interval.
Definition: MSInductLoop.h:331
~MSInductLoop()
Destructor.
void writeXMLDetectorProlog(OutputDevice &dev) const
Opens the XML-output using "detector" as root element.
bool notifyMove(SUMOTrafficObject &veh, double oldPos, double newPos, double newSpeed)
Checks whether the vehicle shall be counted and/or shall still touch this MSMoveReminder.
double getTimeSinceLastDetection() const
Returns the time since the last vehicle left the detector.
double myLastLeaveTime
Leave-time of the last vehicle detected [s].
Definition: MSInductLoop.h:319
const bool myNeedLock
whether internals need to be guarded against concurrent access (GUI or multi threading)
Definition: MSInductLoop.h:316
bool notifyEnter(SUMOTrafficObject &veh, Notification reason, const MSLane *enteredLane=0)
Checks whether the reminder is activated by a vehicle entering the lane.
std::vector< VehicleData > collectVehiclesOnDet(SUMOTime t, bool includeEarly=false, bool leaveTime=false, bool forOccupancy=false) const
Returns vehicle data for vehicles that have been on the detector starting at the given time.
std::map< SUMOTrafficObject *, double > myVehiclesOnDet
Data for vehicles that have entered the detector (vehicle -> enter time)
Definition: MSInductLoop.h:334
SUMOTime getLastDetectionTime() const
return last time a vehicle was on the detector
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.
Representation of a lane in the micro simulation.
Definition: MSLane.h:82
Something on a lane to be noticed about vehicle movement.
MSLane *const myLane
Lane on which the reminder works.
Notification
Definition of a vehicle state.
@ NOTIFICATION_JUNCTION
The vehicle arrived at a junction.
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:171
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:313
double getLength() const
Get vehicle's length [m].
const std::string & getID() const
Returns the id.
Definition: Named.h:73
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:60
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.
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:239
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
Representation of a vehicle, person, or container.
virtual double getPreviousSpeed() const =0
Returns the object's previous speed.
virtual double getSpeed() const =0
Returns the object's current speed.
virtual const MSVehicleType & getVehicleType() const =0
Returns the object's "vehicle" type.
virtual double getBackPositionOnLane(const MSLane *lane) const =0
Get the object's back position along the given lane.
virtual double getPositionOnLane() const =0
Get the object's position along the lane.
static std::string escapeXML(const std::string &orig, const bool maskDoubleHyphen=false)
Replaces the standard escapes by their XML entities.
Struct to store the data of the counted vehicle internally.
Definition: MSInductLoop.h:249
VehicleData(const SUMOTrafficObject &v, double entryTimestep, double leaveTimestep, const bool leftEarly)
Constructor.
double speedM
Speed of the vehicle in [m/s].
Definition: MSInductLoop.h:270