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