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