Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 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 : /****************************************************************************/
14 : /// @file MSE2Collector.cpp
15 : /// @author Christian Roessel
16 : /// @author Daniel Krajzewicz
17 : /// @author Sascha Krieg
18 : /// @author Michael Behrisch
19 : /// @author Robbin Blokpoel
20 : /// @author Jakob Erdmann
21 : /// @author Leonhard Luecken
22 : /// @date Mon Feb 03 2014 10:13 CET
23 : ///
24 : // An areal detector covering a sequence of consecutive lanes
25 : /****************************************************************************/
26 :
27 :
28 : /* TODO:
29 : * tests:
30 : * - subsecond variant, ballistic variant
31 : * allow omitting jam processing (?)
32 : *
33 : * Meso-compatibility? (esp. enteredLane-argument for MSBaseVehicle::notifyEnter() is not treated)
34 : * Compatibility without internal lanes?
35 : * Include leftVehicles into output?
36 : */
37 : #include <config.h>
38 :
39 : #include <cassert>
40 : #include <algorithm>
41 : #ifdef HAVE_FOX
42 : #include <utils/common/ScopedLocker.h>
43 : #endif
44 : #include <microsim/MSLane.h>
45 : #include <microsim/MSEdge.h>
46 : #include <microsim/MSLink.h>
47 : #include <microsim/MSNet.h>
48 : #include <microsim/MSVehicle.h>
49 : #include <microsim/MSVehicleType.h>
50 : #include <microsim/transportables/MSTransportable.h>
51 : #include <microsim/transportables/MSPModel.h>
52 : #include "MSE2Collector.h"
53 :
54 : //#define DEBUG_E2_CONSTRUCTOR
55 : //#define DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
56 : //#define DEBUG_E2_NOTIFY_MOVE
57 : //#define DEBUG_E2_MAKE_VEHINFO
58 : //#define DEBUG_E2_DETECTOR_UPDATE
59 : //#define DEBUG_E2_TIME_ON_DETECTOR
60 : //#define DEBUG_E2_JAMS
61 : //#define DEBUG_E2_XML_OUT
62 : //#define DEBUG_COND (true)
63 : //#define DEBUG_COND (getID()=="e2Detector_e5.601A_1_SAa")
64 : //#define DEBUG_COND (getID()=="702057")
65 : //#define DEBUG_COND (getID()=="det0")
66 :
67 5370 : MSE2Collector::MSE2Collector(const std::string& id,
68 : DetectorUsage usage, MSLane* lane, double startPos, double endPos, double length,
69 : SUMOTime haltingTimeThreshold, double haltingSpeedThreshold, double jamDistThreshold,
70 : const std::string name, const std::string& vTypes,
71 : const std::string& nextEdges,
72 5370 : int detectPersons) :
73 : MSMoveReminder(id, lane, false),
74 : MSDetectorFileOutput(id, vTypes, nextEdges, detectPersons),
75 5370 : myUsage(usage),
76 5370 : myName(name),
77 5370 : myJamHaltingSpeedThreshold(haltingSpeedThreshold),
78 5370 : myJamHaltingTimeThreshold(haltingTimeThreshold),
79 5370 : myJamDistanceThreshold(jamDistThreshold),
80 5370 : myNumberOfEnteredVehicles(0),
81 5370 : myNumberOfSeenVehicles(0),
82 5370 : myNumberOfLeftVehicles(0),
83 5370 : myCurrentVehicleSamples(0),
84 5370 : myCurrentOccupancy(0),
85 5370 : myCurrentMeanSpeed(0),
86 5370 : myCurrentMeanLength(0),
87 5370 : myCurrentJamNo(0),
88 5370 : myCurrentMaxJamLengthInMeters(0),
89 5370 : myCurrentJamLengthInMeters(0),
90 5370 : myCurrentJamLengthInVehicles(0),
91 5370 : myCurrentHaltingsNumber(0),
92 5370 : myPreviousMeanOccupancy(0),
93 5370 : myPreviousMeanSpeed(0),
94 5370 : myPreviousMaxJamLengthInMeters(0),
95 5370 : myPreviousNumberOfSeenVehicles(0),
96 5370 : myOverrideVehNumber(-1) {
97 5370 : reset();
98 :
99 : #ifdef DEBUG_E2_CONSTRUCTOR
100 : if (DEBUG_COND) {
101 : std::cout << "\n" << "Creating MSE2Collector " << id
102 : << " with lane = " << lane->getID()
103 : << " startPos = " << startPos
104 : << " endPos = " << endPos
105 : << " length = " << length
106 : << " haltingTimeThreshold = " << haltingTimeThreshold
107 : << " haltingSpeedThreshold = " << haltingSpeedThreshold
108 : << " jamDistThreshold = " << jamDistThreshold
109 : << std::endl;
110 : }
111 : #endif
112 :
113 : assert(lane != 0);
114 :
115 : // check that exactly one of length, startPos, endPos is invalid
116 5370 : bool lengthInvalid = length == std::numeric_limits<double>::max() || length <= 0;
117 5370 : bool endPosInvalid = endPos == std::numeric_limits<double>::max();
118 : bool posInvalid = startPos == std::numeric_limits<double>::max();
119 :
120 : // check and normalize positions (assure positive values for pos and endPos, snap to lane-ends)
121 5370 : if (lengthInvalid) {
122 : // assume that the detector is only located on a single lane
123 23 : if (posInvalid) {
124 0 : WRITE_WARNING(TL("No valid detector length and start position given. Assuming startPos = 0 and length = end position"));
125 : startPos = 0;
126 : }
127 23 : if (endPosInvalid) {
128 2 : WRITE_WARNING(TL("No valid detector length and end position given. Assuming endPos = lane length and length = endPos-startPos"));
129 : endPos = lane->getLength();
130 : }
131 23 : endPos = endPos < 0 ? lane->getLength() + endPos : endPos;
132 23 : startPos = startPos < 0 ? lane->getLength() + startPos : startPos;
133 23 : bool valid = endPos <= lane->getLength() && 0 <= startPos && startPos < endPos;
134 : if (!valid) {
135 0 : throw InvalidArgument("Error in specification for E2Detector '" + id + "'. Positional argument is malformed. 0 <= pos < endPos <= lane.getLength() is required.");
136 : }
137 : // snap detector ends to lane ends
138 23 : endPos = snap(endPos, lane->getLength(), POSITION_EPS);
139 23 : startPos = snap(startPos, 0., POSITION_EPS);
140 23 : length = endPos - startPos;
141 5347 : } else if (posInvalid) {
142 : // endPosInvalid == false
143 1274 : endPos = endPos < 0 ? lane->getLength() + endPos : endPos;
144 1274 : endPos = snap(endPos, lane->getLength(), POSITION_EPS);
145 : } else {
146 : // posInvalid == false
147 4073 : startPos = startPos < 0 ? lane->getLength() + startPos : startPos;
148 4073 : startPos = snap(startPos, 0., POSITION_EPS);
149 : }
150 :
151 5370 : myStartPos = startPos;
152 5370 : myEndPos = endPos;
153 :
154 : std::vector<MSLane*> lanes;
155 5370 : if (posInvalid) {
156 2548 : lanes = selectLanes(lane, length, "bw");
157 4096 : } else if (endPosInvalid) {
158 8148 : lanes = selectLanes(lane, length, "fw");
159 : } else {
160 : // assuming detector is only located at a single lane
161 22 : lanes.push_back(lane);
162 : }
163 :
164 5370 : initAuxiliaries(lanes);
165 5370 : checkPositioning(endPosInvalid, length);
166 5370 : addDetectorToLanes(lanes);
167 5370 : }
168 :
169 :
170 270 : MSE2Collector::MSE2Collector(const std::string& id,
171 : DetectorUsage usage, std::vector<MSLane*> lanes, double startPos, double endPos,
172 : SUMOTime haltingTimeThreshold, double haltingSpeedThreshold, double jamDistThreshold,
173 : const std::string name, const std::string& vTypes,
174 : const std::string& nextEdges,
175 270 : int detectPersons) :
176 : MSMoveReminder(id, lanes[lanes.size() - 1], false), // assure that lanes.size() > 0 at caller side!!!
177 : MSDetectorFileOutput(id, vTypes, nextEdges, detectPersons),
178 270 : myUsage(usage),
179 270 : myName(name),
180 270 : myFirstLane(lanes[0]),
181 270 : myLastLane(lanes[lanes.size() - 1]),
182 270 : myStartPos(startPos),
183 270 : myEndPos(endPos),
184 270 : myJamHaltingSpeedThreshold(haltingSpeedThreshold),
185 270 : myJamHaltingTimeThreshold(haltingTimeThreshold),
186 270 : myJamDistanceThreshold(jamDistThreshold),
187 270 : myNumberOfEnteredVehicles(0),
188 270 : myNumberOfSeenVehicles(0),
189 270 : myNumberOfLeftVehicles(0),
190 270 : myCurrentVehicleSamples(0),
191 270 : myCurrentOccupancy(0),
192 270 : myCurrentMeanSpeed(0),
193 270 : myCurrentMeanLength(0),
194 270 : myCurrentJamNo(0),
195 270 : myCurrentJamLengthInMeters(0),
196 270 : myCurrentJamLengthInVehicles(0),
197 270 : myCurrentHaltingsNumber(0),
198 270 : myOverrideVehNumber(-1) {
199 270 : reset();
200 :
201 909 : for (std::vector<MSLane*>::const_iterator i = lanes.begin(); i != lanes.end(); ++i) {
202 : assert((*i) != 0);
203 : }
204 :
205 : #ifdef DEBUG_E2_CONSTRUCTOR
206 : if (DEBUG_COND) {
207 : std::cout << "\n" << "Creating MSE2Collector " << id
208 : << " with endLane = " << myLastLane->getID()
209 : << " endPos = " << endPos
210 : << " startLane = " << myFirstLane->getID()
211 : << " startPos = " << startPos
212 : << " haltingTimeThreshold = " << haltingTimeThreshold
213 : << " haltingSpeedThreshold = " << haltingSpeedThreshold
214 : << " jamDistThreshold = " << jamDistThreshold
215 : << std::endl;
216 : }
217 : #endif
218 :
219 270 : myStartPos = myStartPos < 0 ? lanes[0]->getLength() + myStartPos : myStartPos;
220 270 : myEndPos = myEndPos < 0 ? lanes[lanes.size() - 1]->getLength() + myEndPos : myEndPos;
221 :
222 270 : if (myStartPos < POSITION_EPS) {
223 1 : myStartPos = 0;
224 : }
225 270 : if (myEndPos > lanes[lanes.size() - 1]->getLength() - POSITION_EPS) {
226 1 : myEndPos = lanes[lanes.size() - 1]->getLength();
227 : }
228 :
229 :
230 270 : initAuxiliaries(lanes);
231 264 : checkPositioning();
232 264 : addDetectorToLanes(lanes);
233 306 : }
234 :
235 :
236 : void
237 5634 : MSE2Collector::checkPositioning(bool posGiven, double desiredLength) {
238 : // check if detector was truncated
239 5634 : if (desiredLength > 0 && myDetectorLength < desiredLength - NUMERICAL_EPS) {
240 7 : std::stringstream ss;
241 : ss << "Cannot build detector of length " << desiredLength
242 7 : << " because no further continuation lane was found for lane '" << (posGiven ? myLastLane->getID() : myFirstLane->getID())
243 14 : << "'! Truncated detector at length " << myDetectorLength << ".";
244 7 : WRITE_WARNING(ss.str());
245 7 : }
246 :
247 5634 : if (myDetectorLength < POSITION_EPS && (myStartPos > 0. || myEndPos < myLastLane->getLength())) {
248 : // assure minimal detector length
249 6 : double prolong = POSITION_EPS - myDetectorLength;
250 6 : double startPos = MAX2(0., myStartPos - prolong); // new startPos
251 6 : prolong -= myStartPos - startPos;
252 6 : myStartPos = startPos;
253 6 : if (prolong > 0.) {
254 7 : myEndPos = MIN2(myEndPos + prolong, myLastLane->getLength());
255 : }
256 30 : WRITE_WARNING("Adjusted detector positioning to meet requirement length >= " + toString(POSITION_EPS)
257 : + ". New position is [" + toString(myStartPos) + "," + toString(myEndPos) + "]");
258 : }
259 :
260 : // do some regularization snapping...
261 5634 : myStartPos = snap(myStartPos, 0., POSITION_EPS);
262 5634 : myStartPos = snap(myStartPos, myFirstLane->getLength() - POSITION_EPS, POSITION_EPS);
263 5634 : myStartPos = snap(myStartPos, 0., POSITION_EPS);
264 5634 : myEndPos = snap(myEndPos, myLastLane->getLength(), POSITION_EPS);
265 5634 : myEndPos = snap(myEndPos, POSITION_EPS, POSITION_EPS);
266 5634 : myEndPos = snap(myEndPos, myLastLane->getLength(), POSITION_EPS);
267 5634 : recalculateDetectorLength();
268 :
269 : #ifdef DEBUG_E2_CONSTRUCTOR
270 : if (DEBUG_COND) {
271 : std::stringstream ss;
272 : // ss << std::setprecision(32) << myEndPos << " : " << POSITION_EPS;
273 : // std::cout << ss.str() << std::endl;
274 : std::cout << "myStartPos = " << myStartPos << std::endl;
275 : std::cout << "myEndPos = " << myEndPos << std::endl;
276 : std::cout << "myLastLane->getLength() = " << myLastLane->getLength() << std::endl;
277 : }
278 : #endif
279 :
280 :
281 : assert((myStartPos >= POSITION_EPS || myStartPos == 0) && myStartPos < myFirstLane->getLength());
282 : assert(myEndPos <= myLastLane->getLength() - POSITION_EPS || myEndPos == myLastLane->getLength());
283 : assert(myFirstLane != myLastLane || myEndPos - myStartPos > 0);
284 5634 : }
285 :
286 :
287 : double
288 39197 : MSE2Collector::snap(double value, double snapPoint, double snapDist) {
289 39197 : if (fabs(value - snapPoint) < snapDist) {
290 : return snapPoint;
291 : } else {
292 27167 : return value;
293 : }
294 : }
295 :
296 :
297 : void
298 5634 : MSE2Collector::recalculateDetectorLength() {
299 : std::vector<std::string>::const_iterator i;
300 : std::vector<MSLane*> lanes;
301 : // get real lanes
302 2035774 : for (i = myLanes.begin(); i != myLanes.end(); ++i) {
303 2030140 : MSLane* lane = MSLane::dictionary(*i);
304 2030140 : lanes.push_back(lane);
305 : }
306 :
307 : // sum up their lengths
308 : std::vector<MSLane*>::const_iterator j;
309 : MSLane* previous = nullptr;
310 5634 : myDetectorLength = 0;
311 2035774 : for (j = lanes.begin(); j != lanes.end(); ++j) {
312 : // lane length
313 2030140 : myDetectorLength += (*j)->getLength();
314 2030140 : if (previous != nullptr && !MSGlobals::gUsingInternalLanes) {
315 : // eventually link length
316 14 : myDetectorLength += previous->getLinkTo(*j)->getLength();
317 : }
318 2030140 : previous = *j;
319 : }
320 : // subtract uncovered area on first and last lane
321 5634 : myDetectorLength -= myStartPos;
322 5634 : myDetectorLength -= myLastLane->getLength() - myEndPos;
323 :
324 : #ifdef DEBUG_E2_CONSTRUCTOR
325 : if (DEBUG_COND) {
326 : std::cout << "Total detector length after recalculation = " << myDetectorLength << std::endl;
327 : }
328 : #endif
329 5634 : }
330 :
331 :
332 11021 : MSE2Collector::~MSE2Collector() {
333 : // clear move notifications
334 5630 : clearState(SUMOTime_MAX);
335 27911 : }
336 :
337 :
338 : std::vector<MSLane*>
339 5348 : MSE2Collector::selectLanes(MSLane* lane, double length, std::string dir) {
340 : // direction of detector extension
341 : assert(dir == "fw" || dir == "bw");
342 5348 : bool fw = dir == "fw";
343 : double linkLength = 0; // linkLength (used if no internal lanes are present)
344 : bool subtractedLinkLength = false; // whether linkLength was subtracted during the last iteration.
345 :
346 : #ifdef DEBUG_E2_CONSTRUCTOR
347 : if (DEBUG_COND) {
348 : std::cout << "\n" << "selectLanes()" << (fw ? "(forward)" : "(backward)") << std::endl;
349 : }
350 : #endif
351 : std::vector<MSLane*> lanes;
352 : // Selected lanes are stacked into vector 'lanes'. If dir == "bw" lanes will be reversed after this is done.
353 : // The length is reduced while adding lanes to the detector
354 : // First we adjust the starting value for length (in the first iteration, the whole length of the first considered lane is subtracted,
355 : // while it might only be partially covered by the detector)
356 5348 : if (fw) {
357 : assert(myStartPos != std::numeric_limits<double>::max());
358 4074 : length += myStartPos;
359 : } else {
360 : assert(myEndPos != std::numeric_limits<double>::max());
361 1274 : length += lane->getLength() - myEndPos;
362 : }
363 : length = MAX2(POSITION_EPS, length); // this assures to add at least one lane to lanes
364 2034511 : while (length >= POSITION_EPS && lane != nullptr) {
365 : // Break loop for length <= NUMERICAL_EPS to avoid placement of very small
366 : // detector piece on the end or beginning of one lane due to numerical rounding errors.
367 2029163 : lanes.push_back(lane);
368 : #ifdef DEBUG_E2_CONSTRUCTOR
369 : if (DEBUG_COND) {
370 : std::cout << "Added lane " << lane->getID()
371 : << " (length: " << lane->getLength() << ")" << std::endl;
372 : }
373 : #endif
374 :
375 2029163 : length -= lane->getLength();
376 :
377 : // proceed to upstream predecessor
378 2029163 : if (fw) {
379 2027279 : lane = lane->getCanonicalSuccessorLane();
380 : } else {
381 1884 : lane = lane->getCanonicalPredecessorLane();
382 : }
383 :
384 :
385 : subtractedLinkLength = false;
386 2029163 : if (lane != nullptr && !MSGlobals::gUsingInternalLanes && length > POSITION_EPS) {
387 : // In case wher no internal lanes are used,
388 : // take into account the link length for the detector range
389 : linkLength = 0;
390 8 : if (fw) {
391 8 : linkLength = lanes.back()->getLinkTo(lane)->getLength();
392 : } else {
393 0 : linkLength = lane->getLinkTo(lanes.back())->getLength();
394 : }
395 8 : length -= linkLength;
396 : subtractedLinkLength = true;
397 : }
398 :
399 :
400 : #ifdef DEBUG_E2_CONSTRUCTOR
401 : if (DEBUG_COND) {
402 : if (lane != 0) {
403 : std::cout << (fw ? "Successor lane: " : "Predecessor lane: ") << "'" << lane->getID() << "'";
404 : }
405 : std::cout << std::endl;
406 : }
407 : #endif
408 : }
409 :
410 5348 : if (subtractedLinkLength) {
411 : // if the link's length was subtracted during the last step,
412 : // the start/endPos would lie on a non-existing internal lane,
413 : // therefore revert and truncate detector part on the non-existing internal lane.
414 0 : length += linkLength;
415 : }
416 :
417 :
418 : // 1) At this point a negative <length> means that not the whole last stored lane lanes[lanes.size()-1]
419 : // should be added to the detector, but the detector should spare out a part with length = -<length>
420 : // If this part is too small (of length < POSITION_EPS) we take the whole lane
421 : // 2) The whole lane is also taken for the case that <length> is positive. This corresponds to on
422 : // of three situations: i) <length> < POSITION_EPS (break condition -> don't take too small pieces on the next lane)
423 : // ii&iii) <length> >= POS_EPSILON may arise either if no continuation lane was found (lane==0), or
424 : // in case of not using internal lanes if the detector end/start falls on a link.
425 : // In all cases we take the whole last lane.
426 5348 : if (fw) {
427 4074 : if (length > -POSITION_EPS) {
428 2188 : myEndPos = lanes[lanes.size() - 1]->getLength();
429 1886 : } else if (length < 0) {
430 1886 : myEndPos = lanes[lanes.size() - 1]->getLength() + length;
431 : }
432 : } else {
433 1274 : if (length > -POSITION_EPS) {
434 386 : myStartPos = 0;
435 888 : } else if (length < 0) {
436 888 : myStartPos = -length;
437 : }
438 : }
439 :
440 : // reverse lanes if lane selection was backwards
441 5348 : if (!fw) {
442 : std::reverse(lanes.begin(), lanes.end());
443 : }
444 :
445 5348 : return lanes;
446 0 : }
447 :
448 : void
449 5634 : MSE2Collector::addDetectorToLanes(std::vector<MSLane*>& lanes) {
450 : #ifdef DEBUG_E2_CONSTRUCTOR
451 : if (DEBUG_COND) {
452 : std::cout << "\n" << "Adding detector " << myID << " to lanes:" << std::endl;
453 : }
454 : #endif
455 2035774 : for (std::vector<MSLane*>::iterator l = lanes.begin(); l != lanes.end(); ++l) {
456 2030140 : (*l)->addMoveReminder(this);
457 : #ifdef DEBUG_E2_CONSTRUCTOR
458 : if (DEBUG_COND) {
459 : std::cout << (*l)->getID() << std::endl;
460 : }
461 : #endif
462 : }
463 5634 : }
464 :
465 : void
466 5640 : MSE2Collector::initAuxiliaries(std::vector<MSLane*>& lanes) {
467 : // Checks integrity of myLanes, adds internal-lane information, inits myLength, myFirstLane, myLastLane, myOffsets, myEndPos/myStartPos
468 5640 : myFirstLane = lanes[0];
469 5640 : myLastLane = lanes[lanes.size() - 1];
470 :
471 : #ifdef DEBUG_E2_CONSTRUCTOR
472 : if (DEBUG_COND) {
473 : std::cout << "\n" << "Initializing auxiliaries:"
474 : << "\nFirst lane: " << myFirstLane->getID() << " (startPos = " << myStartPos << ")"
475 : << "\nLast lane: " << myLastLane->getID() << " (endPos = " << myEndPos << ")"
476 : << std::endl;
477 : }
478 : #endif
479 :
480 : // Init myOffsets and myDetectorLength.
481 : // The loop below runs through the given lanes assuming the possibility that only non-internal lanes are given
482 : // or at least not all relevant internal lanes are considered. During this a new, complete list of lane ids is
483 : // built into myLanes.
484 : myLanes.clear();
485 :
486 : // myDetectorLength will be increased in the loop below, always giving
487 : // the offset of the currently considered lane to the detector start
488 5640 : myDetectorLength = -myStartPos;
489 : myOffsets.clear();
490 :
491 : // loop over detector lanes and accumulate offsets with respect to the first lane's begin
492 : // (these will be corrected afterwards by subtracting the start position.)
493 : std::vector<MSLane*>::iterator il = lanes.begin();
494 :
495 : // start on an internal lane?
496 : // (This may happen if specifying the detector by its upstream
497 : // length starting from a given end position)
498 5640 : const MSLane* internal = (*il)->isInternal() ? *il : nullptr;
499 :
500 : #ifdef DEBUG_E2_CONSTRUCTOR
501 : if (DEBUG_COND) {
502 : std::cout << "\n" << "Initializing offsets:" << std::endl;
503 : }
504 : #endif
505 :
506 : while (true) {
507 : // Consider the next internal lanes
508 2029400 : while (internal != nullptr) {
509 754 : myLanes.push_back(internal->getID());
510 754 : myOffsets.push_back(myDetectorLength);
511 :
512 : #ifdef DEBUG_E2_CONSTRUCTOR
513 : if (DEBUG_COND) {
514 : std::cout << "Offset for lane " << internal->getID() << " = " << myDetectorLength
515 : << std::endl;
516 : }
517 : #endif
518 :
519 754 : myDetectorLength += internal->getLength();
520 754 : if (internal->getID() == myLastLane->getID()) {
521 : break;
522 : }
523 :
524 : // There should be a unique continuation for each internal lane
525 : assert(internal->getLinkCont().size() == 1);
526 :
527 754 : internal = internal->getLinkCont()[0]->getViaLaneOrLane();
528 754 : if (!internal->isInternal()) {
529 : // passed the junction
530 : internal = nullptr;
531 : break;
532 : }
533 : }
534 :
535 : // Consider the next non-internal lane
536 : // This is the first lane in the first iteration, if it is non-internal
537 : // However, it can equal myLanes.end() if the myLastLane is internal. In that case we break.
538 :
539 : // Move il to next non-internal
540 2029814 : while (il != lanes.end() && (*il)->isInternal()) {
541 : il++;
542 : }
543 2029392 : if (il == lanes.end()) {
544 : break;
545 : }
546 :
547 : // There is still a non-internal lane to consider
548 2029392 : MSLane* lane = *il;
549 2029392 : myLanes.push_back(lane->getID());
550 :
551 : #ifdef DEBUG_E2_CONSTRUCTOR
552 : if (DEBUG_COND) {
553 : std::cout << "Offset for lane " << lane->getID() << " = " << myDetectorLength
554 : << std::endl;
555 : }
556 : #endif
557 :
558 : // Offset to detector start for this lane
559 2029392 : myOffsets.push_back(myDetectorLength);
560 :
561 : // Add the lanes length to the detector offset
562 2029392 : myDetectorLength += lane->getLength();
563 :
564 : // Get the next lane if this lane isn't the last one
565 2029392 : if (++il == lanes.end()) {
566 : break;
567 : }
568 :
569 2023758 : if ((*il)->isInternal()) {
570 : // next lane in myLanes is internal
571 240 : internal = *il;
572 240 : continue;
573 : }
574 :
575 : // find the connection to next
576 2023518 : const MSLink* link = lane->getLinkTo(*il);
577 2023518 : if (link == nullptr) {
578 12 : throw InvalidArgument("Lanes '" + lane->getID() + "' and '" + (*il)->getID() + "' are not consecutive in definition of e2Detector '" + getID() + "'");
579 : }
580 :
581 2023512 : if (!MSGlobals::gUsingInternalLanes) {
582 14 : myDetectorLength += link->getLength();
583 : } else {
584 : internal = link->getViaLane();
585 : }
586 : }
587 :
588 : // Subtract distance not covered on the last considered lane
589 5634 : bool fw = myEndPos == std::numeric_limits<double>::max();
590 5634 : if (fw) {
591 0 : myDetectorLength -= myStartPos;
592 : } else {
593 5634 : myDetectorLength -= myLastLane->getLength() - myEndPos;
594 : }
595 :
596 : #ifdef DEBUG_E2_CONSTRUCTOR
597 : if (DEBUG_COND) {
598 : std::cout << "Total detector length after initAuxiliaries() = " << myDetectorLength << std::endl;
599 : }
600 : #endif
601 :
602 : // make lanes a complete list including internal lanes
603 5634 : lanes = getLanes();
604 5634 : }
605 :
606 :
607 : std::vector<MSLane*>
608 100399 : MSE2Collector::getLanes() {
609 : std::vector<MSLane*> res;
610 2725390 : for (std::vector<std::string>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
611 2624991 : res.push_back(MSLane::dictionary(*i));
612 : }
613 100399 : return res;
614 0 : }
615 :
616 :
617 : bool
618 105120127 : MSE2Collector::notifyMove(SUMOTrafficObject& veh, double oldPos,
619 : double newPos, double newSpeed) {
620 :
621 105120127 : if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
622 : bool keep = false;
623 270 : MSBaseVehicle& v = dynamic_cast<MSBaseVehicle&>(veh);
624 540 : for (MSTransportable* p : v.getPersons()) {
625 270 : keep = notifyMove(*p, oldPos, newPos, newSpeed);
626 : }
627 270 : return keep;
628 : }
629 : #ifdef HAVE_FOX
630 105119857 : ScopedLocker<> lock(myNotificationMutex, MSGlobals::gNumSimThreads > 1);
631 : #endif
632 : VehicleInfoMap::iterator vi = myVehicleInfos.find(veh.getID());
633 105119857 : if (vi == myVehicleInfos.end()) {
634 0 : const std::string objectType = veh.isPerson() ? "Person" : "Vehicle";
635 0 : if (myNextEdges.size() > 0) {
636 0 : WRITE_WARNING(objectType + " '" + veh.getID() + "' appeared inside detector '" + getID() + "' after previously being filtered out. time=" + time2string(SIMSTEP) + ".");
637 : } else {
638 0 : WRITE_WARNING(objectType + " '" + veh.getID() + "' suddenly appeared inside detector '" + getID() + "'. time=" + time2string(SIMSTEP) + ".");
639 : }
640 : return false;
641 : }
642 :
643 : const std::string& vehID = veh.getID();
644 105119857 : VehicleInfo& vehInfo = *(vi->second);
645 :
646 : // position relative to the detector start
647 105119857 : double relPos = vehInfo.entryOffset + newPos;
648 :
649 : // update current distance to the detector end
650 105119857 : vehInfo.distToDetectorEnd = myDetectorLength - relPos;
651 :
652 : #ifdef DEBUG_E2_NOTIFY_MOVE
653 : if (DEBUG_COND) {
654 : std::cout << "\n" << SIMTIME
655 : << " MSE2Collector::notifyMove() (detID = " << myID << " on lane '" << myLane->getID() << "')"
656 : << " called by vehicle '" << vehID << "'"
657 : << " at relative position " << relPos
658 : << ", distToDetectorEnd = " << vehInfo.distToDetectorEnd << std::endl;
659 : }
660 : #endif
661 :
662 : // Check whether vehicle has reached the detector begin
663 105119857 : if (relPos <= 0) {
664 : // detector not yet reached, request being informed further
665 : #ifdef DEBUG_E2_NOTIFY_MOVE
666 : if (DEBUG_COND) {
667 : std::cout << "Vehicle has not yet reached the detector start position." << std::endl;
668 : }
669 : #endif
670 : return true;
671 47199017 : } else if (!vehInfo.hasEntered) {
672 584007 : vehInfo.hasEntered = true;
673 584007 : myNumberOfEnteredVehicles++;
674 584007 : myNumberOfSeenVehicles++;
675 : }
676 :
677 :
678 : // determine whether vehicle has moved beyond the detector's end
679 47199017 : bool vehPassedDetectorEnd = - vehInfo.exitOffset <= newPos - veh.getVehicleType().getLength();
680 :
681 : // determine whether vehicle has been on the detector at all
682 47199017 : bool vehicleEnteredLaneAfterDetector = vehPassedDetectorEnd && (-vehInfo.exitOffset <= oldPos - veh.getVehicleType().getLength());
683 : // ... if not, dont create any notification at all
684 : if (vehicleEnteredLaneAfterDetector) {
685 : #ifdef DEBUG_E2_NOTIFY_MOVE
686 : if (DEBUG_COND) {
687 : std::cout << "Vehicle entered lane behind detector." << std::endl;
688 : }
689 : #endif
690 : } else {
691 47198953 : myMoveNotifications.push_back(makeMoveNotification(veh, oldPos, newPos, newSpeed, vehInfo));
692 : }
693 :
694 :
695 47199017 : if (vehPassedDetectorEnd) {
696 : #ifdef DEBUG_E2_NOTIFY_MOVE
697 : if (DEBUG_COND) {
698 : std::cout << "Vehicle has left the detector longitudinally." << std::endl;
699 : }
700 : #endif
701 : // Vehicle is beyond the detector, unsubscribe and register removal from myVehicleInfos
702 : myLeftVehicles.insert(vehID);
703 : return false;
704 : } else {
705 : // Receive further notifications
706 : return true;
707 : }
708 : }
709 :
710 : bool
711 777914 : MSE2Collector::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
712 : #ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
713 : if (DEBUG_COND) {
714 : std::cout << "\n" << SIMTIME << " notifyLeave() (detID = " << myID << " on lane '" << myLane->getID() << "')"
715 : << "called by vehicle '" << veh.getID() << "'" << std::endl;
716 : }
717 : #endif
718 :
719 : #ifdef HAVE_FOX
720 777914 : ScopedLocker<> lock(myNotificationMutex, MSGlobals::gNumSimThreads > 1);
721 : #endif
722 777914 : if (reason == MSMoveReminder::NOTIFICATION_JUNCTION && !veh.isPerson()) {
723 : // vehicle left lane via junction, unsubscription and registering in myLeftVehicles when
724 : // moving beyond the detector end is controlled in notifyMove.
725 : #ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
726 : if (DEBUG_COND) {
727 : std::cout << SIMTIME << " Left longitudinally (along junction) -> keep subscription [handle exit in notifyMove()]" << std::endl;
728 : }
729 : #endif
730 :
731 770977 : if (enteredLane == nullptr || std::find(myLanes.begin(), myLanes.end(), enteredLane->getID()) == myLanes.end()) {
732 : // Entered lane is not part of the detector
733 : VehicleInfoMap::iterator vi = myVehicleInfos.find(veh.getID());
734 : // Determine exit offset, where vehicle left the detector
735 712127 : double exitOffset = vi->second->entryOffset - myOffsets[vi->second->currentOffsetIndex] - vi->second->currentLane->getLength();
736 1423008 : vi->second->exitOffset = MAX2(vi->second->exitOffset, exitOffset);
737 : #ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
738 : if (DEBUG_COND) {
739 : std::cout << SIMTIME << " Vehicle '" << veh.getID() << "' leaves the detector. Exit offset = " << vi->second->exitOffset << std::endl;
740 : }
741 : #endif
742 : }
743 :
744 770977 : return true;
745 : } else {
746 : VehicleInfoMap::iterator vi = myVehicleInfos.find(veh.getID());
747 6937 : if (vi != myVehicleInfos.end()) {
748 : // erase vehicle, which leaves in a non-longitudinal way, immediately
749 5627 : if (vi->second->hasEntered) {
750 1198 : myNumberOfLeftVehicles++;
751 : }
752 5627 : delete vi->second;
753 : myVehicleInfos.erase(vi);
754 : #ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
755 : if (DEBUG_COND) {
756 : std::cout << SIMTIME << " Left non-longitudinally (lanechange, teleport, parking, etc) -> discard subscription" << std::endl;
757 : }
758 : #endif
759 : } else {
760 : assert(veh.isPerson());
761 : }
762 : return false;
763 : }
764 : }
765 :
766 :
767 : bool
768 653247 : MSE2Collector::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
769 : #ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
770 : if (DEBUG_COND) {
771 : std::cout << std::endl << SIMTIME << " notifyEnter() (detID = " << myID << " on lane '" << myLane->getID() << "')"
772 : << " called by vehicle '" << veh.getID()
773 : << "' entering lane '" << (enteredLane != 0 ? enteredLane->getID() : "NULL") << "'" << std::endl;
774 : }
775 : #endif
776 : // notifyEnter() should only be called for lanes of the detector
777 : assert(std::find(myLanes.begin(), myLanes.end(), enteredLane->getID()) != myLanes.end());
778 : assert(veh.getLane() == enteredLane || !veh.isVehicle());
779 :
780 : // vehicles must be kept if the "inductionloop" wants to detect passeengers
781 653247 : if (!vehicleApplies(veh) && (veh.isPerson() || myDetectPersons <= (int)PersonMode::WALK)) {
782 : // That's not my type...
783 : return false;
784 : }
785 648118 : if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
786 : bool keep = false;
787 40 : MSBaseVehicle& v = dynamic_cast<MSBaseVehicle&>(veh);
788 80 : for (MSTransportable* p : v.getPersons()) {
789 40 : keep = notifyEnter(*p, reason, enteredLane);
790 : }
791 40 : return keep;
792 : }
793 :
794 : // determine whether the vehicle entered the lane behind the detector end
795 : // e.g. due to lane change manoeuver
796 648078 : if (reason != NOTIFICATION_JUNCTION) {
797 383200 : const double vehBackPos = veh.getBackPositionOnLane(enteredLane);
798 383200 : bool vehEnteredBehindDetectorEnd = (enteredLane == myLastLane) && myEndPos <= vehBackPos;
799 : if (vehEnteredBehindDetectorEnd) {
800 : // this vehicle cannot influence detector readings, do not subscribe
801 : // to move notifications
802 : #ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
803 : if (DEBUG_COND) {
804 : std::cout << "Vehicle entered the lane behind the detector, ignoring it." << std::endl;
805 : std::cout << "(myEndPos = " << this->myEndPos << ", veh.getBackPositionOnLane() = " << vehBackPos << ")" << std::endl;
806 : }
807 : #endif
808 : return false;
809 : }
810 : }
811 :
812 : #ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
813 : if (DEBUG_COND) {
814 : if (veh.isVehicle() && !dynamic_cast<SUMOVehicle&>(veh).isOnRoad()) {
815 : // Vehicle is teleporting over the edge
816 : std::cout << "Vehicle is off road (teleporting over edge)..." << std::endl;
817 : }
818 : }
819 : #endif
820 :
821 : #ifdef HAVE_FOX
822 647869 : ScopedLocker<> lock(myNotificationMutex, MSGlobals::gNumSimThreads > 1);
823 : #endif
824 : const std::string& vehID = veh.getID();
825 : VehicleInfoMap::iterator vi = myVehicleInfos.find(vehID);
826 647869 : if (vi != myVehicleInfos.end()) {
827 : // Register move current offset to the next lane
828 58859 : if (vi->second->currentLane != enteredLane) {
829 58850 : vi->second->currentOffsetIndex++;
830 58850 : vi->second->currentLane = enteredLane;
831 : }
832 :
833 : #ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
834 : if (DEBUG_COND) {
835 : std::cout << SIMTIME << " Vehicle '" << veh.getID() << "' on lane '" << veh.getLane()->getID()
836 : << "' already known. No new VehicleInfo is created.\n"
837 : << "enteredLane = " << enteredLane->getID() << "\nmyLanes[vi->offset] = " << myLanes[vi->second->currentOffsetIndex]
838 : << std::endl;
839 : }
840 : #endif
841 : assert(myLanes[vi->second->currentOffsetIndex] == enteredLane->getID());
842 :
843 : // but don't add a second subscription for another lane
844 58859 : return false;
845 : }
846 :
847 :
848 :
849 : #ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
850 : if (DEBUG_COND) {
851 : std::cout << SIMTIME << " Adding VehicleInfo for vehicle '" << veh.getID() << "'." << std::endl;
852 : }
853 : #endif
854 :
855 : // Add vehicle info
856 589010 : myVehicleInfos.insert(std::make_pair(vehID, makeVehicleInfo(veh, enteredLane)));
857 : // Subscribe to vehicle's movement notifications
858 589010 : return true;
859 : }
860 :
861 :
862 : MSE2Collector::VehicleInfo*
863 589010 : MSE2Collector::makeVehicleInfo(const SUMOTrafficObject& veh, const MSLane* enteredLane) const {
864 : // The vehicle's distance to the detector end
865 589010 : int j = (int)(std::find(myLanes.begin(), myLanes.end(), enteredLane->getID()) - myLanes.begin());
866 : assert(j >= 0 && j < (int)myLanes.size());
867 589010 : double entryOffset = myOffsets[j];
868 589010 : double distToDetectorEnd = myDetectorLength - (entryOffset + veh.getPositionOnLane());
869 589010 : bool onDetector = -entryOffset < veh.getPositionOnLane() && distToDetectorEnd > -veh.getVehicleType().getLength();
870 :
871 : #ifdef DEBUG_E2_MAKE_VEHINFO
872 : if (DEBUG_COND) {
873 : std::cout << SIMTIME << " Making VehicleInfo for vehicle '" << veh.getID() << "'."
874 : << "\ndistToDetectorEnd = " << distToDetectorEnd
875 : << "\nveh.getPositionOnLane() = " << veh.getPositionOnLane()
876 : << "\nentry lane offset (lane begin from detector begin) = " << entryOffset
877 : << std::endl;
878 : }
879 : #endif
880 589010 : return new VehicleInfo(veh.getID(), veh.getVehicleType().getID(), veh.getVehicleType().getLength(), veh.getVehicleType().getMinGap(), enteredLane, entryOffset, j,
881 1767030 : myOffsets[j] - myDetectorLength, distToDetectorEnd, onDetector);
882 : }
883 :
884 :
885 : void
886 77072 : MSE2Collector::notifyMovePerson(MSTransportable* p, int dir, double pos) {
887 77072 : if (personApplies(*p, dir)) {
888 55248 : const double newSpeed = p->getSpeed();
889 55248 : const double newPos = (dir == MSPModel::FORWARD
890 55248 : ? pos
891 : // position relative to detector end position
892 15552 : : myEndPos - (pos - myEndPos));
893 55248 : const double oldPos = newPos - SPEED2DIST(newSpeed);
894 55248 : if (oldPos - p->getVehicleType().getLength() <= myEndPos) {
895 32824 : notifyMove(*p, oldPos, newPos, newSpeed);
896 : }
897 : }
898 77072 : }
899 :
900 :
901 : void
902 8392077 : MSE2Collector::detectorUpdate(const SUMOTime /* step */) {
903 :
904 8392077 : if (myDetectPersons != (int)PersonMode::NONE) {
905 93889 : if (myLanes.size() > 1) {
906 : /// code is more complicated because we have to make persons with
907 : //dir=BACKWARD send a virtual forward-lane-sequence
908 18 : throw ProcessError(TL("Multi-lane e2Detector does not support detecting persons yet"));
909 : }
910 187760 : for (MSLane* lane : getLanes()) {
911 93880 : if (lane->hasPedestrians()) {
912 117636 : for (MSTransportable* p : myLane->getEdge().getPersons()) {
913 105544 : if (p->getLane() == lane && vehicleApplies(*p)) {
914 77072 : notifyMovePerson(p, p->getDirection(), p->getPositionOnLane());
915 : }
916 : }
917 : }
918 93880 : }
919 : }
920 :
921 : #ifdef DEBUG_E2_DETECTOR_UPDATE
922 : if (DEBUG_COND) {
923 : std::cout << "\n" << SIMTIME << " detectorUpdate() for detector '" << myID << "'"
924 : << "\nmyCurrentMeanSpeed = " << myCurrentMeanSpeed
925 : << "\nmyCurrentMeanLength = " << myCurrentMeanLength
926 : << "\nmyNumberOfEnteredVehicles = " << myNumberOfEnteredVehicles
927 : << "\nmyNumberOfLeftVehicles = " << myNumberOfLeftVehicles
928 : << "\nmyNumberOfSeenVehicles = " << myNumberOfSeenVehicles
929 : << std::endl;
930 : }
931 : #endif
932 :
933 : // sort myMoveNotifications (required for jam processing) ascendingly according to vehicle's distance to the detector end
934 : // (min = myMoveNotifications[0].distToDetectorEnd)
935 8392068 : std::sort(myMoveNotifications.begin(), myMoveNotifications.end(), compareMoveNotification);
936 :
937 : // reset values concerning current time step (these are updated in integrateMoveNotification() and aggregateOutputValues())
938 8392068 : myCurrentVehicleSamples = 0;
939 8392068 : myCurrentMeanSpeed = 0;
940 8392068 : myCurrentMeanLength = 0;
941 8392068 : myCurrentStartedHalts = 0;
942 8392068 : myCurrentHaltingsNumber = 0;
943 :
944 8392068 : JamInfo* currentJam = nullptr;
945 : std::vector<JamInfo*> jams;
946 : std::map<std::string, SUMOTime> haltingVehicles;
947 : std::map<std::string, SUMOTime> intervalHaltingVehicles;
948 :
949 : // go through the list of vehicles positioned on the detector
950 55591021 : for (std::vector<MoveNotificationInfo*>::iterator i = myMoveNotifications.begin(); i != myMoveNotifications.end(); ++i) {
951 : // The ID of the vehicle that has sent this notification in the last step
952 47198953 : const std::string& vehID = (*i)->id;
953 : VehicleInfoMap::iterator vi = myVehicleInfos.find(vehID);
954 :
955 47198953 : if (vi == myVehicleInfos.end()) {
956 : // The vehicle has already left the detector by lanechange, teleport, etc. (not longitudinal)
957 1114 : integrateMoveNotification(nullptr, *i);
958 : } else {
959 : // Add move notification infos to detector values and VehicleInfo
960 47197839 : integrateMoveNotification(vi->second, *i);
961 : }
962 : // construct jam structure
963 47198953 : bool isInJam = checkJam(i, haltingVehicles, intervalHaltingVehicles);
964 47198953 : buildJam(isInJam, i, currentJam, jams);
965 : }
966 :
967 : // extract some aggregated values from the jam structure
968 8392068 : processJams(jams, currentJam);
969 :
970 : // Aggregate and normalize values for the detector output
971 8392068 : aggregateOutputValues();
972 :
973 : // save information about halting vehicles
974 : myHaltingVehicleDurations = haltingVehicles;
975 : myIntervalHaltingVehicleDurations = intervalHaltingVehicles;
976 :
977 : #ifdef DEBUG_E2_DETECTOR_UPDATE
978 : if (DEBUG_COND) {
979 : std::cout << "\n" << SIMTIME << " Current lanes for vehicles still on or approaching the detector:" << std::endl;
980 : }
981 : #endif
982 : // update current and entered lanes for remaining vehicles
983 : VehicleInfoMap::iterator iv;
984 : for (iv = myVehicleInfos.begin(); iv != myVehicleInfos.end(); ++iv) {
985 : #ifdef DEBUG_E2_DETECTOR_UPDATE
986 : if (DEBUG_COND) {
987 : std::cout << " Vehicle '" << iv->second->id << "'" << ": '"
988 : << iv->second->currentLane->getID() << "'"
989 : << std::endl;
990 : }
991 : #endif
992 : }
993 :
994 : #ifdef DEBUG_E2_DETECTOR_UPDATE
995 : if (DEBUG_COND) {
996 : std::cout << SIMTIME << " Discarding vehicles that have left the detector:" << std::endl;
997 : }
998 : #endif
999 : // Remove the vehicles that have left the detector
1000 : std::set<std::string>::const_iterator i;
1001 8971159 : for (i = myLeftVehicles.begin(); i != myLeftVehicles.end(); ++i) {
1002 : VehicleInfoMap::iterator j = myVehicleInfos.find(*i);
1003 579091 : delete j->second;
1004 : myVehicleInfos.erase(*i);
1005 579091 : myNumberOfLeftVehicles++;
1006 : #ifdef DEBUG_E2_DETECTOR_UPDATE
1007 : if (DEBUG_COND) {
1008 : std::cout << "Erased vehicle '" << *i << "'" << std::endl;
1009 : }
1010 : #endif
1011 : }
1012 : myLeftVehicles.clear();
1013 :
1014 : // reset move notifications
1015 55591021 : for (std::vector<MoveNotificationInfo*>::iterator j = myMoveNotifications.begin(); j != myMoveNotifications.end(); ++j) {
1016 47198953 : delete *j;
1017 : }
1018 : myMoveNotifications.clear();
1019 8392068 : }
1020 :
1021 :
1022 : void
1023 8392068 : MSE2Collector::aggregateOutputValues() {
1024 8392068 : myTimeSamples += 1;
1025 : // compute occupancy values (note myCurrentMeanLength is still not normalized here, but holds the sum of all vehicle lengths)
1026 8392068 : const double currentOccupancy = myCurrentMeanLength / myDetectorLength * (double) 100.;
1027 8392068 : myCurrentOccupancy = currentOccupancy;
1028 8392068 : myOccupancySum += currentOccupancy;
1029 8392068 : myMaxOccupancy = MAX2(myMaxOccupancy, currentOccupancy);
1030 : // compute jam values
1031 8392068 : myMeanMaxJamInVehicles += myCurrentMaxJamLengthInVehicles;
1032 8392068 : myMeanMaxJamInMeters += myCurrentMaxJamLengthInMeters;
1033 8392068 : myMaxJamInVehicles = MAX2(myMaxJamInVehicles, myCurrentMaxJamLengthInVehicles);
1034 15626321 : myMaxJamInMeters = MAX2(myMaxJamInMeters, myCurrentMaxJamLengthInMeters);
1035 : // compute information about vehicle numbers
1036 8392068 : const int numVehicles = (int)myMoveNotifications.size();
1037 8392068 : myMeanVehicleNumber += numVehicles;
1038 8392068 : myMaxVehicleNumber = MAX2(numVehicles, myMaxVehicleNumber);
1039 : // norm current values
1040 8392068 : myCurrentMeanSpeed = numVehicles != 0 ? myCurrentMeanSpeed / myCurrentVehicleSamples : -1;
1041 8392068 : myCurrentMeanLength = numVehicles != 0 ? myCurrentMeanLength / (double) numVehicles : -1;
1042 8392068 : }
1043 :
1044 :
1045 :
1046 : void
1047 47198953 : MSE2Collector::integrateMoveNotification(VehicleInfo* vi, const MoveNotificationInfo* mni) {
1048 :
1049 : #ifdef DEBUG_E2_DETECTOR_UPDATE
1050 : if (DEBUG_COND) {
1051 : std::cout << SIMTIME << " integrateMoveNotification() for vehicle '" << mni->id << "'"
1052 : << "\ntimeOnDetector = " << mni->timeOnDetector
1053 : << "\nlengthOnDetector = " << mni->lengthOnDetector
1054 : << "\ntimeLoss = " << mni->timeLoss
1055 : << "\nspeed = " << mni->speed
1056 : << std::endl;
1057 : }
1058 : #endif
1059 :
1060 : // Accumulate detector values
1061 47198953 : myVehicleSamples += mni->timeOnDetector;
1062 47198953 : myTotalTimeLoss += mni->timeLoss;
1063 47198953 : mySpeedSum += mni->speed * mni->timeOnDetector;
1064 47198953 : myCurrentVehicleSamples += mni->timeOnDetector;
1065 47198953 : myCurrentMeanSpeed += mni->speed * mni->timeOnDetector;
1066 47198953 : myCurrentMeanLength += mni->lengthOnDetector;
1067 :
1068 47198953 : if (vi != nullptr) {
1069 : // Accumulate individual values for the vehicle.
1070 : // @note vi==0 occurs, if the vehicle info has been erased at
1071 : // notifyLeave() in case of a non-longitudinal exit (lanechange, teleport, etc.)
1072 47197839 : vi->totalTimeOnDetector += mni->timeOnDetector;
1073 47197839 : vi->accumulatedTimeLoss += mni->timeLoss;
1074 47197839 : vi->lastAccel = mni->accel;
1075 47197839 : vi->lastSpeed = mni->speed;
1076 47197839 : vi->lastPos = myStartPos + vi->entryOffset + mni->newPos;
1077 47197839 : vi->onDetector = mni->onDetector;
1078 : }
1079 47198953 : }
1080 :
1081 :
1082 :
1083 : MSE2Collector::MoveNotificationInfo*
1084 47198953 : MSE2Collector::makeMoveNotification(const SUMOTrafficObject& veh, double oldPos, double newPos, double newSpeed, const VehicleInfo& vehInfo) const {
1085 : #ifdef DEBUG_E2_NOTIFY_MOVE
1086 : if (DEBUG_COND) {
1087 : std::cout << SIMTIME << " makeMoveNotification() for vehicle '" << veh.getID() << "'"
1088 : << " oldPos = " << oldPos << " newPos = " << newPos << " newSpeed = " << newSpeed
1089 : << std::endl;
1090 : }
1091 : #endif
1092 :
1093 : // Timefraction in [0,TS] the vehicle has spend on the detector in the last step
1094 : double timeOnDetector;
1095 : // Note that at this point, vehInfo.currentLane points to the lane at the beginning of the last timestep,
1096 : // and vehInfo.enteredLanes is a list of lanes entered in the last timestep
1097 : double timeLoss;
1098 47198953 : calculateTimeLossAndTimeOnDetector(veh, oldPos, newPos, vehInfo, timeOnDetector, timeLoss);
1099 :
1100 : // The length of the part of the vehicle on the detector at the end of the last time step
1101 : // may be shorter than vehicle's length if its back reaches out
1102 47198953 : double lengthOnDetector = MAX2(MIN2(vehInfo.length, newPos + vehInfo.entryOffset), 0.);
1103 :
1104 : // XXX: Fulfulling the specifications of the documentation (lengthOnDetector = time integral
1105 : // over length of the vehicle's part on the detector) would be much more cumbersome.
1106 47198953 : double distToExit = -vehInfo.exitOffset - newPos;
1107 : // Eventually decrease further to account for the front reaching out
1108 47198953 : lengthOnDetector = MAX2(0., lengthOnDetector + MIN2(0., distToExit));
1109 :
1110 : // whether the vehicle is still on the detector at the end of the time step
1111 47198953 : bool stillOnDetector = -distToExit < vehInfo.length;
1112 :
1113 : #ifdef DEBUG_E2_NOTIFY_MOVE
1114 : if (DEBUG_COND) {
1115 : std::cout << SIMTIME << " lengthOnDetector = " << lengthOnDetector
1116 : << "\nvehInfo.exitOffset = " << vehInfo.exitOffset
1117 : << " vehInfo.entryOffset = " << vehInfo.entryOffset
1118 : << " distToExit = " << distToExit
1119 : << std::endl;
1120 : }
1121 : #endif
1122 :
1123 : /* Store new infos */
1124 47198953 : return new MoveNotificationInfo(veh.getID(), oldPos, newPos, newSpeed, veh.getAcceleration(),
1125 47198953 : myDetectorLength - (vehInfo.entryOffset + newPos),
1126 94397906 : timeOnDetector, lengthOnDetector, timeLoss, stillOnDetector);
1127 : }
1128 :
1129 : void
1130 47198953 : MSE2Collector::buildJam(bool isInJam, std::vector<MoveNotificationInfo*>::const_iterator mni, JamInfo*& currentJam, std::vector<JamInfo*>& jams) {
1131 : #ifdef DEBUG_E2_JAMS
1132 : if (DEBUG_COND) {
1133 : std::cout << SIMTIME << " buildJam() for vehicle '" << (*mni)->id << "'" << std::endl;
1134 : }
1135 : #endif
1136 47198953 : if (isInJam) {
1137 : // The vehicle is in a jam;
1138 : // it may be a new one or already an existing one
1139 33310487 : if (currentJam == nullptr) {
1140 : #ifdef DEBUG_E2_JAMS
1141 : if (DEBUG_COND) {
1142 : std::cout << SIMTIME << " vehicle '" << (*mni)->id << "' forms the start of the first jam" << std::endl;
1143 : }
1144 : #endif
1145 : // the vehicle is the first vehicle in a jam
1146 2037935 : currentJam = new JamInfo();
1147 2037935 : currentJam->firstStandingVehicle = mni;
1148 : } else {
1149 : // ok, we have a jam already. But - maybe it is too far away
1150 : // ... honestly, I can hardly find a reason for doing this,
1151 : // but jams were defined this way in an earlier version...
1152 31272552 : MoveNotificationInfo* lastVeh = *currentJam->lastStandingVehicle;
1153 31272552 : MoveNotificationInfo* currVeh = *mni;
1154 31272552 : if (lastVeh->distToDetectorEnd - currVeh->distToDetectorEnd > myJamDistanceThreshold) {
1155 : #ifdef DEBUG_E2_JAMS
1156 : if (DEBUG_COND) {
1157 : std::cout << SIMTIME << " vehicle '" << (*mni)->id << "' forms the start of a new jam" << std::endl;
1158 : }
1159 : #endif
1160 : // yep, yep, yep - it's a new one...
1161 : // close the frist, build a new
1162 0 : jams.push_back(currentJam);
1163 0 : currentJam = new JamInfo();
1164 0 : currentJam->firstStandingVehicle = mni;
1165 : }
1166 : }
1167 33310487 : currentJam->lastStandingVehicle = mni;
1168 : } else {
1169 : // the vehicle is not part of a jam...
1170 : // maybe we have to close an already computed jam
1171 13888466 : if (currentJam != nullptr) {
1172 : #ifdef DEBUG_E2_JAMS
1173 : if (DEBUG_COND) {
1174 : std::cout << SIMTIME << " Closing current jam." << std::endl;
1175 : }
1176 : #endif
1177 937880 : jams.push_back(currentJam);
1178 937880 : currentJam = nullptr;
1179 : }
1180 : }
1181 47198953 : }
1182 :
1183 :
1184 : bool
1185 47198953 : MSE2Collector::checkJam(std::vector<MoveNotificationInfo*>::const_iterator mni, std::map<std::string, SUMOTime>& haltingVehicles, std::map<std::string, SUMOTime>& intervalHaltingVehicles) {
1186 : #ifdef DEBUG_E2_JAMS
1187 : if (DEBUG_COND) {
1188 : std::cout << SIMTIME << " CheckJam() for vehicle '" << (*mni)->id << "'" << std::endl;
1189 : }
1190 : #endif
1191 : // jam-checking begins
1192 : bool isInJam = false;
1193 : // first, check whether the vehicle is slow enough to be counted as halting
1194 47198953 : if ((*mni)->speed < myJamHaltingSpeedThreshold) {
1195 34021680 : myCurrentHaltingsNumber++;
1196 : // we have to track the time it was halting;
1197 : // so let's look up whether it was halting before and compute the overall halting time
1198 34021680 : bool wasHalting = myHaltingVehicleDurations.count((*mni)->id) > 0;
1199 : if (wasHalting) {
1200 33243574 : haltingVehicles[(*mni)->id] = myHaltingVehicleDurations[(*mni)->id] + DELTA_T;
1201 33243574 : intervalHaltingVehicles[(*mni)->id] = myIntervalHaltingVehicleDurations[(*mni)->id] + DELTA_T;
1202 : } else {
1203 : #ifdef DEBUG_E2_JAMS
1204 : if (DEBUG_COND) {
1205 : std::cout << SIMTIME << " vehicle '" << (*mni)->id << "' starts halting." << std::endl;
1206 : }
1207 : #endif
1208 778106 : haltingVehicles[(*mni)->id] = DELTA_T;
1209 778106 : intervalHaltingVehicles[(*mni)->id] = DELTA_T;
1210 778106 : myCurrentStartedHalts++;
1211 778106 : myStartedHalts++;
1212 : }
1213 : // we now check whether the halting time is large enough
1214 34021680 : if (haltingVehicles[(*mni)->id] > myJamHaltingTimeThreshold) {
1215 : // yep --> the vehicle is a part of a jam
1216 : isInJam = true;
1217 : }
1218 : } else {
1219 : // is not standing anymore; keep duration information
1220 26354546 : std::map<std::string, SUMOTime>::iterator v = myHaltingVehicleDurations.find((*mni)->id);
1221 13177273 : if (v != myHaltingVehicleDurations.end()) {
1222 773621 : myPastStandingDurations.push_back(v->second);
1223 : myHaltingVehicleDurations.erase(v);
1224 : }
1225 13177273 : v = myIntervalHaltingVehicleDurations.find((*mni)->id);
1226 13177273 : if (v != myIntervalHaltingVehicleDurations.end()) {
1227 773621 : myPastIntervalStandingDurations.push_back((*v).second);
1228 : myIntervalHaltingVehicleDurations.erase(v);
1229 : }
1230 : }
1231 : #ifdef DEBUG_E2_JAMS
1232 : if (DEBUG_COND) {
1233 : std::cout << SIMTIME << " vehicle '" << (*mni)->id << "'" << (isInJam ? "is jammed." : "is not jammed.") << std::endl;
1234 : }
1235 : #endif
1236 47198953 : return isInJam;
1237 : }
1238 :
1239 :
1240 : void
1241 8392068 : MSE2Collector::processJams(std::vector<JamInfo*>& jams, JamInfo* currentJam) {
1242 : // push last jam
1243 8392068 : if (currentJam != nullptr) {
1244 1100055 : jams.push_back(currentJam);
1245 1100055 : currentJam = nullptr;
1246 : }
1247 :
1248 : #ifdef DEBUG_E2_JAMS
1249 : if (DEBUG_COND) {
1250 : std::cout << "\n" << SIMTIME << " processJams()"
1251 : << "\nNumber of jams: " << jams.size() << std::endl;
1252 : }
1253 : #endif
1254 :
1255 : // process jam information
1256 8392068 : myCurrentMaxJamLengthInMeters = 0;
1257 8392068 : myCurrentMaxJamLengthInVehicles = 0;
1258 8392068 : myCurrentJamLengthInMeters = 0;
1259 8392068 : myCurrentJamLengthInVehicles = 0;
1260 10430003 : for (std::vector<JamInfo*>::const_iterator i = jams.begin(); i != jams.end(); ++i) {
1261 : // compute current jam's values
1262 2037935 : MoveNotificationInfo* lastVeh = *((*i)->lastStandingVehicle);
1263 2037935 : MoveNotificationInfo* firstVeh = *((*i)->firstStandingVehicle);
1264 2037935 : const double jamLengthInMeters = MAX2(lastVeh->distToDetectorEnd, 0.) -
1265 2037935 : MAX2(firstVeh->distToDetectorEnd, 0.) +
1266 2037935 : lastVeh->lengthOnDetector;
1267 2037935 : const int jamLengthInVehicles = (int) distance((*i)->firstStandingVehicle, (*i)->lastStandingVehicle) + 1;
1268 : // apply them to the statistics
1269 2037935 : myCurrentMaxJamLengthInMeters = MAX2(myCurrentMaxJamLengthInMeters, jamLengthInMeters);
1270 2037935 : myCurrentMaxJamLengthInVehicles = MAX2(myCurrentMaxJamLengthInVehicles, jamLengthInVehicles);
1271 2037935 : myJamLengthInMetersSum += jamLengthInMeters;
1272 2037935 : myJamLengthInVehiclesSum += jamLengthInVehicles;
1273 2037935 : myCurrentJamLengthInMeters += jamLengthInMeters;
1274 2037935 : myCurrentJamLengthInVehicles += jamLengthInVehicles;
1275 : #ifdef DEBUG_E2_JAMS
1276 : if (DEBUG_COND) {
1277 : std::cout << SIMTIME << " processing jam nr." << ((int) distance((std::vector<JamInfo*>::const_iterator) jams.begin(), i) + 1)
1278 : << "\njamLengthInMeters = " << jamLengthInMeters
1279 : << " jamLengthInVehicles = " << jamLengthInVehicles
1280 : << std::endl;
1281 : }
1282 : #endif
1283 : }
1284 8392068 : myCurrentJamNo = (int) jams.size();
1285 :
1286 : // clean up jam structure
1287 10430003 : for (std::vector<JamInfo*>::iterator i = jams.begin(); i != jams.end(); ++i) {
1288 2037935 : delete *i;
1289 : }
1290 8392068 : }
1291 :
1292 : void
1293 47198953 : MSE2Collector::calculateTimeLossAndTimeOnDetector(const SUMOTrafficObject& veh, double oldPos, double newPos, const VehicleInfo& vi, double& timeOnDetector, double& timeLoss) const {
1294 : assert(veh.getID() == vi.id);
1295 : assert(newPos + vi.entryOffset >= 0);
1296 :
1297 47198953 : if (oldPos == newPos) {
1298 : // vehicle is stopped
1299 33515721 : timeLoss = TS;
1300 33515721 : timeOnDetector = TS;
1301 33515721 : return;
1302 : }
1303 :
1304 : // Eventual positional offset of the detector start from the lane's start
1305 13683232 : double entryPos = MAX2(-vi.entryOffset, 0.);
1306 : // Time of this vehicle entering the detector in the last time step
1307 : double entryTime = 0;
1308 : // Take into account the time before entering the detector, if there is.
1309 13683232 : if (oldPos < entryPos) {
1310 : // Vehicle entered the detector in the last step, either traversing the detector start or somewhere in the middle.
1311 580289 : entryTime = MSCFModel::passingTime(oldPos, entryPos, newPos, veh.getPreviousSpeed(), veh.getSpeed());
1312 : }
1313 : // speed at detector entry
1314 13683232 : double entrySpeed = MSCFModel::speedAfterTime(entryTime, veh.getPreviousSpeed(), newPos - oldPos);
1315 : // Calculate time spent on detector until reaching newPos or a detector exit
1316 13683232 : double exitPos = MIN2(newPos, -vi.exitOffset + vi.length);
1317 : assert(entryPos < exitPos);
1318 :
1319 : // calculate vehicle's time spent on the detector
1320 : double exitTime;
1321 13683232 : if (exitPos == newPos) {
1322 13104273 : exitTime = TS;
1323 : } else {
1324 578959 : exitTime = MSCFModel::passingTime(oldPos, exitPos, newPos, veh.getPreviousSpeed(), veh.getSpeed());
1325 : }
1326 :
1327 : // Vehicle's Speed when leaving the detector
1328 13683232 : double exitSpeed = MSCFModel::speedAfterTime(exitTime, veh.getPreviousSpeed(), newPos - oldPos);
1329 :
1330 : // Maximal speed on vehicle's current lane (== lane before last time step)
1331 : // Note: this disregards the possibility of different maximal speeds on different traversed lanes.
1332 : // (we accept this as discretization error)
1333 13683232 : double vmax = MAX2(veh.getLane()->getVehicleMaxSpeed(&veh), NUMERICAL_EPS);
1334 :
1335 : // Time loss suffered on the detector
1336 13683232 : timeOnDetector = exitTime - entryTime;
1337 27338464 : timeLoss = MAX2(0., timeOnDetector * (vmax - (entrySpeed + exitSpeed) / 2) / vmax);
1338 :
1339 : #ifdef DEBUG_E2_TIME_ON_DETECTOR
1340 : if (DEBUG_COND) {
1341 : std::cout << SIMTIME << " calculateTimeLoss() for vehicle '" << veh.getID() << "'"
1342 : << " oldPos = " << oldPos << " newPos = " << newPos
1343 : << " entryPos = " << entryPos << " exitPos = " << exitPos
1344 : << " timeOnDetector = " << timeOnDetector
1345 : << " timeLoss = " << timeLoss
1346 : << std::endl;
1347 : }
1348 : #endif
1349 : }
1350 :
1351 :
1352 : void
1353 4094 : MSE2Collector::writeXMLDetectorProlog(OutputDevice& dev) const {
1354 8188 : dev.writeXMLHeader("detector", "det_e2_file.xsd");
1355 4094 : }
1356 :
1357 : void
1358 296182 : MSE2Collector::writeXMLOutput(OutputDevice& dev, SUMOTime startTime, SUMOTime stopTime) {
1359 296182 : const double meanSpeed = getIntervalMeanSpeed();
1360 296182 : const double meanOccupancy = getIntervalOccupancy();
1361 296182 : myPreviousMeanOccupancy = meanOccupancy;
1362 296182 : myPreviousMeanSpeed = meanSpeed;
1363 296182 : myPreviousMaxJamLengthInMeters = myMaxJamInMeters;
1364 296182 : myPreviousNumberOfSeenVehicles = myNumberOfSeenVehicles;
1365 :
1366 296182 : if (dev.isNull()) {
1367 5870 : reset();
1368 5870 : return;
1369 : }
1370 580624 : dev << " <interval begin=\"" << time2string(startTime) << "\" end=\"" << time2string(stopTime) << "\" " << "id=\"" << getID() << "\" ";
1371 :
1372 :
1373 290312 : const double meanJamLengthInMeters = myTimeSamples != 0 ? myMeanMaxJamInMeters / (double) myTimeSamples : 0;
1374 290312 : const double meanJamLengthInVehicles = myTimeSamples != 0 ? myMeanMaxJamInVehicles / (double) myTimeSamples : 0;
1375 290312 : const double meanVehicleNumber = myTimeSamples != 0 ? (double) myMeanVehicleNumber / (double) myTimeSamples : 0;
1376 290312 : const double meanTimeLoss = myNumberOfSeenVehicles != 0 ? myTotalTimeLoss / myNumberOfSeenVehicles : -1;
1377 :
1378 : SUMOTime haltingDurationSum = 0;
1379 : SUMOTime maxHaltingDuration = 0;
1380 : int haltingNo = 0;
1381 945317 : for (std::vector<SUMOTime>::iterator i = myPastStandingDurations.begin(); i != myPastStandingDurations.end(); ++i) {
1382 655005 : haltingDurationSum += (*i);
1383 : maxHaltingDuration = MAX2(maxHaltingDuration, (*i));
1384 655005 : haltingNo++;
1385 : }
1386 5208048 : for (std::map<std::string, SUMOTime> ::iterator i = myHaltingVehicleDurations.begin(); i != myHaltingVehicleDurations.end(); ++i) {
1387 4917736 : haltingDurationSum += (*i).second;
1388 : maxHaltingDuration = MAX2(maxHaltingDuration, (*i).second);
1389 4917736 : haltingNo++;
1390 : }
1391 290312 : const SUMOTime meanHaltingDuration = haltingNo != 0 ? haltingDurationSum / haltingNo : 0;
1392 :
1393 : SUMOTime intervalHaltingDurationSum = 0;
1394 : SUMOTime intervalMaxHaltingDuration = 0;
1395 : int intervalHaltingNo = 0;
1396 945317 : for (std::vector<SUMOTime>::iterator i = myPastIntervalStandingDurations.begin(); i != myPastIntervalStandingDurations.end(); ++i) {
1397 655005 : intervalHaltingDurationSum += (*i);
1398 : intervalMaxHaltingDuration = MAX2(intervalMaxHaltingDuration, (*i));
1399 655005 : intervalHaltingNo++;
1400 : }
1401 5208048 : for (std::map<std::string, SUMOTime> ::iterator i = myIntervalHaltingVehicleDurations.begin(); i != myIntervalHaltingVehicleDurations.end(); ++i) {
1402 4917736 : intervalHaltingDurationSum += (*i).second;
1403 : intervalMaxHaltingDuration = MAX2(intervalMaxHaltingDuration, (*i).second);
1404 4917736 : intervalHaltingNo++;
1405 : }
1406 290312 : const SUMOTime intervalMeanHaltingDuration = intervalHaltingNo != 0 ? intervalHaltingDurationSum / intervalHaltingNo : 0;
1407 :
1408 : #ifdef DEBUG_E2_XML_OUT
1409 : if (DEBUG_COND) {
1410 : std::stringstream ss;
1411 : ss << "sampledSeconds=\"" << myVehicleSamples << "\" "
1412 : << "myTimeSamples=\"" << myTimeSamples << "\" "
1413 : << "myOccupancySum=\"" << myOccupancySum << "\" "
1414 : << "myMeanVehicleNumber=\"" << myMeanVehicleNumber << "\" "
1415 : << "nVehEntered=\"" << myNumberOfEnteredVehicles << "\" "
1416 : << "meanSpeed=\"" << meanSpeed << "\"";
1417 : std::cout << ss.str() << std::endl;
1418 : }
1419 : #endif
1420 :
1421 :
1422 290312 : dev << "sampledSeconds=\"" << myVehicleSamples << "\" "
1423 290312 : << "nVehEntered=\"" << myNumberOfEnteredVehicles << "\" "
1424 290312 : << "nVehLeft=\"" << myNumberOfLeftVehicles << "\" "
1425 290312 : << "nVehSeen=\"" << myNumberOfSeenVehicles << "\" "
1426 290312 : << "meanSpeed=\"" << meanSpeed << "\" "
1427 290312 : << "meanTimeLoss=\"" << meanTimeLoss << "\" "
1428 290312 : << "meanOccupancy=\"" << meanOccupancy << "\" "
1429 290312 : << "maxOccupancy=\"" << myMaxOccupancy << "\" "
1430 290312 : << "meanMaxJamLengthInVehicles=\"" << meanJamLengthInVehicles << "\" "
1431 290312 : << "meanMaxJamLengthInMeters=\"" << meanJamLengthInMeters << "\" "
1432 290312 : << "maxJamLengthInVehicles=\"" << myMaxJamInVehicles << "\" "
1433 290312 : << "maxJamLengthInMeters=\"" << myMaxJamInMeters << "\" "
1434 290312 : << "jamLengthInVehiclesSum=\"" << myJamLengthInVehiclesSum << "\" "
1435 290312 : << "jamLengthInMetersSum=\"" << myJamLengthInMetersSum << "\" "
1436 290312 : << "meanHaltingDuration=\"" << STEPS2TIME(meanHaltingDuration) << "\" "
1437 290312 : << "maxHaltingDuration=\"" << STEPS2TIME(maxHaltingDuration) << "\" "
1438 290312 : << "haltingDurationSum=\"" << STEPS2TIME(haltingDurationSum) << "\" "
1439 290312 : << "meanIntervalHaltingDuration=\"" << STEPS2TIME(intervalMeanHaltingDuration) << "\" "
1440 290312 : << "maxIntervalHaltingDuration=\"" << STEPS2TIME(intervalMaxHaltingDuration) << "\" "
1441 290312 : << "intervalHaltingDurationSum=\"" << STEPS2TIME(intervalHaltingDurationSum) << "\" "
1442 290312 : << "startedHalts=\"" << myStartedHalts << "\" "
1443 290312 : << "meanVehicleNumber=\"" << meanVehicleNumber << "\" "
1444 290312 : << "maxVehicleNumber=\"" << myMaxVehicleNumber << "\" "
1445 290312 : << "/>\n";
1446 :
1447 290312 : reset();
1448 : }
1449 :
1450 : void
1451 301878 : MSE2Collector::reset() {
1452 301878 : myVehicleSamples = 0;
1453 301878 : myTotalTimeLoss = 0.;
1454 301878 : myNumberOfEnteredVehicles = 0;
1455 301878 : myNumberOfSeenVehicles -= myNumberOfLeftVehicles;
1456 301878 : myNumberOfLeftVehicles = 0;
1457 301878 : myMaxVehicleNumber = 0;
1458 :
1459 301878 : mySpeedSum = 0;
1460 301878 : myStartedHalts = 0;
1461 301878 : myJamLengthInMetersSum = 0;
1462 301878 : myJamLengthInVehiclesSum = 0;
1463 301878 : myOccupancySum = 0;
1464 301878 : myMaxOccupancy = 0;
1465 301878 : myMeanMaxJamInVehicles = 0;
1466 301878 : myMeanMaxJamInMeters = 0;
1467 301878 : myMaxJamInVehicles = 0;
1468 301878 : myMaxJamInMeters = 0;
1469 301878 : myTimeSamples = 0;
1470 301878 : myMeanVehicleNumber = 0;
1471 5221613 : for (std::map<std::string, SUMOTime>::iterator i = myIntervalHaltingVehicleDurations.begin(); i != myIntervalHaltingVehicleDurations.end(); ++i) {
1472 4919735 : (*i).second = 0;
1473 : }
1474 : myPastStandingDurations.clear();
1475 : myPastIntervalStandingDurations.clear();
1476 301878 : }
1477 :
1478 :
1479 : int
1480 1316732 : MSE2Collector::getCurrentVehicleNumber() const {
1481 : int result = 0;
1482 1316732 : if (myOverrideVehNumber >= 0) {
1483 : result = myOverrideVehNumber;
1484 : } else {
1485 17186000 : for (VehicleInfoMap::const_iterator it = myVehicleInfos.begin(); it != myVehicleInfos.end(); it++) {
1486 15869328 : if (it->second->onDetector) {
1487 2494590 : result++;
1488 : }
1489 : }
1490 : }
1491 1316732 : return result;
1492 : }
1493 :
1494 : void
1495 25 : MSE2Collector::overrideVehicleNumber(int num) {
1496 25 : myOverrideVehNumber = num;
1497 25 : }
1498 :
1499 :
1500 :
1501 : std::vector<std::string>
1502 620 : MSE2Collector::getCurrentVehicleIDs() const {
1503 : std::vector<std::string> ret;
1504 973 : for (VehicleInfoMap::const_iterator i = myVehicleInfos.begin(); i != myVehicleInfos.end(); ++i) {
1505 353 : if (i->second->onDetector) {
1506 201 : ret.push_back(i->second->id);
1507 : }
1508 : }
1509 620 : std::sort(ret.begin(), ret.end());
1510 620 : return ret;
1511 0 : }
1512 :
1513 :
1514 : std::vector<MSE2Collector::VehicleInfo*>
1515 1703352 : MSE2Collector::getCurrentVehicles() const {
1516 : std::vector<VehicleInfo*> res;
1517 : VehicleInfoMap::const_iterator i;
1518 4068140 : for (i = myVehicleInfos.begin(); i != myVehicleInfos.end(); ++i) {
1519 2364788 : if (i->second->onDetector) {
1520 1499571 : res.push_back(i->second);
1521 : }
1522 : }
1523 1703352 : return res;
1524 0 : }
1525 :
1526 :
1527 :
1528 : int
1529 0 : MSE2Collector::getEstimatedCurrentVehicleNumber(double speedThreshold) const {
1530 :
1531 : // double distance = std::numeric_limits<double>::max();
1532 0 : double thresholdSpeed = myLane->getSpeedLimit() / speedThreshold;
1533 :
1534 : int count = 0;
1535 0 : for (VehicleInfoMap::const_iterator it = myVehicleInfos.begin();
1536 0 : it != myVehicleInfos.end(); it++) {
1537 0 : if (it->second->onDetector) {
1538 : // if (it->position < distance) {
1539 : // distance = it->position;
1540 : // }
1541 : // const double realDistance = myLane->getLength() - distance; // the closer vehicle get to the light the greater is the distance
1542 0 : const double realDistance = it->second->distToDetectorEnd;
1543 0 : if (it->second->lastSpeed <= thresholdSpeed || it->second->lastAccel > 0) { //TODO speed less half of the maximum speed for the lane NEED TUNING
1544 0 : count = (int)(realDistance / (it->second->length + it->second->minGap)) + 1;
1545 : }
1546 : }
1547 : }
1548 :
1549 0 : return count;
1550 : }
1551 :
1552 : double
1553 0 : MSE2Collector::getEstimateQueueLength() const {
1554 :
1555 0 : if (myVehicleInfos.empty()) {
1556 : return 0;
1557 : }
1558 :
1559 : double distance = 0;
1560 : double realDistance = 0;
1561 : bool flowing = true;
1562 0 : for (VehicleInfoMap::const_iterator it = myVehicleInfos.begin();
1563 0 : it != myVehicleInfos.end(); it++) {
1564 0 : if (it->second->onDetector && it->second->totalTimeOnDetector > 0) {
1565 : // double distanceTemp = myLane->getLength() - distance;
1566 0 : if (it->second->lastSpeed <= myJamHaltingSpeedThreshold) {
1567 0 : distance = MAX2(it->second->distToDetectorEnd, distance);
1568 0 : realDistance = distance + it->second->length;
1569 : flowing = false;
1570 : }
1571 : // DBG(
1572 : // std::ostringstream str;
1573 : // str << time2string(MSNet::getInstance()->getCurrentTimeStep())
1574 : // << " MSE2Collector::getEstimateQueueLength::"
1575 : // << " lane " << myLane->getID()
1576 : // << " vehicle " << it->second.id
1577 : // << " positionOnLane " << it->second.position
1578 : // << " vel " << it->second.speed
1579 : // << " realDistance " << realDistance;
1580 : // WRITE_MESSAGE(str.str());
1581 : // )
1582 : }
1583 : }
1584 0 : if (flowing) {
1585 : return 0;
1586 : } else {
1587 : return realDistance;
1588 : }
1589 : }
1590 :
1591 :
1592 : void
1593 5650 : MSE2Collector::clearState(SUMOTime /* step */) {
1594 5650 : for (std::vector<MoveNotificationInfo*>::iterator j = myMoveNotifications.begin(); j != myMoveNotifications.end(); ++j) {
1595 0 : delete *j;
1596 : }
1597 : myMoveNotifications.clear();
1598 :
1599 : // clear vehicle infos
1600 9942 : for (VehicleInfoMap::iterator j = myVehicleInfos.begin(); j != myVehicleInfos.end(); ++j) {
1601 4292 : delete j->second;
1602 : }
1603 : myVehicleInfos.clear();
1604 5650 : }
1605 :
1606 : /****************************************************************************/
|