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