|
SUMO - Simulation of Urban MObility
|
00001 /****************************************************************************/ 00011 // An areal (along a single lane) detector 00012 /****************************************************************************/ 00013 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/ 00014 // Copyright (C) 2001-2012 DLR (http://www.dlr.de/) and contributors 00015 /****************************************************************************/ 00016 // 00017 // This file is part of SUMO. 00018 // SUMO is free software: you can redistribute it and/or modify 00019 // it under the terms of the GNU General Public License as published by 00020 // the Free Software Foundation, either version 3 of the License, or 00021 // (at your option) any later version. 00022 // 00023 /****************************************************************************/ 00024 00025 00026 // =========================================================================== 00027 // included modules 00028 // =========================================================================== 00029 #ifdef _MSC_VER 00030 #include <windows_config.h> 00031 #else 00032 #include <config.h> 00033 #endif 00034 00035 #include <algorithm> 00036 #include "MSE2Collector.h" 00037 #include <microsim/MSLane.h> 00038 #include <microsim/MSVehicleType.h> 00039 00040 #ifdef CHECK_MEMORY_LEAKS 00041 #include <foreign/nvwa/debug_new.h> 00042 #endif // CHECK_MEMORY_LEAKS 00043 00044 00045 // =========================================================================== 00046 // method definitions 00047 // =========================================================================== 00048 MSE2Collector::MSE2Collector(const std::string& id, DetectorUsage usage, 00049 MSLane* const lane, SUMOReal startPos, SUMOReal detLength, 00050 SUMOTime haltingTimeThreshold, 00051 SUMOReal haltingSpeedThreshold, 00052 SUMOReal jamDistThreshold) 00053 : MSMoveReminder(lane), MSDetectorFileOutput(id), 00054 myJamHaltingSpeedThreshold(haltingSpeedThreshold), 00055 myJamHaltingTimeThreshold(haltingTimeThreshold), 00056 myJamDistanceThreshold(jamDistThreshold), 00057 myStartPos(startPos), myEndPos(startPos + detLength), 00058 myUsage(usage), 00059 myCurrentOccupancy(0), myCurrentMeanSpeed(-1), myCurrentJamNo(0), 00060 myCurrentMaxJamLengthInMeters(0), myCurrentMaxJamLengthInVehicles(0), 00061 myCurrentJamLengthInMeters(0), myCurrentJamLengthInVehicles(0), myCurrentStartedHalts(0) 00062 00063 { 00064 assert(myLane != 0); 00065 assert(myStartPos >= 0 && myStartPos < myLane->getLength()); 00066 assert(myEndPos - myStartPos > 0 && myEndPos <= myLane->getLength()); 00067 reset(); 00068 } 00069 00070 00071 MSE2Collector::~MSE2Collector() { 00072 myKnownVehicles.clear(); 00073 } 00074 00075 00076 bool 00077 MSE2Collector::notifyMove(SUMOVehicle& veh, SUMOReal oldPos, 00078 SUMOReal newPos, SUMOReal) { 00079 if (newPos < myStartPos) { 00080 // detector not yet reached 00081 return true; 00082 } 00083 if (newPos >= myStartPos && oldPos < myStartPos) { 00084 if (find(myKnownVehicles.begin(), myKnownVehicles.end(), &veh) == myKnownVehicles.end()) { 00085 myKnownVehicles.push_back(&veh); 00086 } 00087 } 00088 if (newPos - veh.getVehicleType().getLengthWithGap() > myEndPos) { 00089 std::list<SUMOVehicle*>::iterator i = find(myKnownVehicles.begin(), myKnownVehicles.end(), &veh); 00090 if (i != myKnownVehicles.end()) { 00091 myKnownVehicles.erase(i); 00092 } 00093 return false; 00094 } 00095 return true; 00096 } 00097 00098 00099 bool 00100 MSE2Collector::notifyLeave(SUMOVehicle& veh, SUMOReal lastPos, MSMoveReminder::Notification reason) { 00101 if (reason != MSMoveReminder::NOTIFICATION_JUNCTION || (lastPos >= myStartPos && lastPos - veh.getVehicleType().getLengthWithGap() < myEndPos)) { 00102 std::list<SUMOVehicle*>::iterator i = find(myKnownVehicles.begin(), myKnownVehicles.end(), &veh); 00103 if (i != myKnownVehicles.end()) { 00104 myKnownVehicles.erase(i); 00105 } 00106 return false; 00107 } 00108 return true; 00109 } 00110 00111 00112 bool 00113 MSE2Collector::notifyEnter(SUMOVehicle& veh, MSMoveReminder::Notification) { 00114 if (veh.getPositionOnLane() >= myStartPos && veh.getPositionOnLane() - veh.getVehicleType().getLengthWithGap() < myEndPos) { 00115 // vehicle is on detector 00116 myKnownVehicles.push_back(&veh); 00117 return true; 00118 } 00119 if (veh.getPositionOnLane() - veh.getVehicleType().getLengthWithGap() > myEndPos) { 00120 // vehicle is beyond detector 00121 return false; 00122 } 00123 // vehicle is in front of detector 00124 return true; 00125 } 00126 00127 00128 void 00129 MSE2Collector::reset() { 00130 mySpeedSum = 0; 00131 myStartedHalts = 0; 00132 myJamLengthInMetersSum = 0; 00133 myJamLengthInVehiclesSum = 0; 00134 myVehicleSamples = 0; 00135 myOccupancySum = 0; 00136 myMaxOccupancy = 0; 00137 myMeanMaxJamInVehicles = 0; 00138 myMeanMaxJamInMeters = 0; 00139 myMaxJamInVehicles = 0; 00140 myMaxJamInMeters = 0; 00141 myTimeSamples = 0; 00142 myMeanVehicleNumber = 0; 00143 myMaxVehicleNumber = 0; 00144 for (std::map<SUMOVehicle*, SUMOTime>::iterator i = myIntervalHaltingVehicleDurations.begin(); i != myIntervalHaltingVehicleDurations.end(); ++i) { 00145 (*i).second = 0; 00146 } 00147 myPastStandingDurations.clear(); 00148 myPastIntervalStandingDurations.clear(); 00149 } 00150 00151 00152 00153 void 00154 MSE2Collector::detectorUpdate(const SUMOTime step) { 00155 JamInfo* currentJam = 0; 00156 std::map<SUMOVehicle*, SUMOTime> haltingVehicles; 00157 std::map<SUMOVehicle*, SUMOTime> intervalHaltingVehicles; 00158 std::vector<JamInfo*> jams; 00159 00160 SUMOReal lengthSum = 0; 00161 myCurrentMeanSpeed = 0; 00162 myCurrentMeanLength = 0; 00163 myCurrentStartedHalts = 0; 00164 00165 // go through the (sorted) list of vehicles positioned on the detector 00166 // sum up values and prepare the list of jams 00167 myKnownVehicles.sort(by_vehicle_position_sorter(getLane())); 00168 for (std::list<SUMOVehicle*>::const_iterator i = myKnownVehicles.begin(); i != myKnownVehicles.end(); ++i) { 00169 MSVehicle* veh = static_cast<MSVehicle*>(*i); 00170 00171 SUMOReal length = veh->getVehicleType().getLengthWithGap(); 00172 if (veh->getLane() == getLane()) { 00173 if (veh->getPositionOnLane() - veh->getVehicleType().getLengthWithGap() < myStartPos) { 00174 // vehicle entered detector partially 00175 length -= (veh->getVehicleType().getLengthWithGap() - (veh->getPositionOnLane() - myStartPos)); 00176 } 00177 if (veh->getPositionOnLane() > myEndPos && veh->getPositionOnLane() - veh->getVehicleType().getLengthWithGap() <= myEndPos) { 00178 // vehicle left detector partially 00179 length -= (veh->getPositionOnLane() - myEndPos); 00180 } 00181 } else { 00182 // ok, the vehicle is only partially still on the detector, has already moved to the 00183 // next lane; still, we do not know how far away it is 00184 assert(veh == myLane->getPartialOccupator()); 00185 length = myEndPos - myLane->getPartialOccupatorEnd(); 00186 } 00187 assert(length >= 0); 00188 00189 mySpeedSum += veh->getSpeed(); 00190 myCurrentMeanSpeed += veh->getSpeed(); 00191 lengthSum += length; 00192 myCurrentMeanLength += length; 00193 00194 // jam-checking begins 00195 bool isInJam = false; 00196 // first, check whether the vehicle is slow enough to be states as halting 00197 if (veh->getSpeed() < myJamHaltingSpeedThreshold) { 00198 // we have to track the time it was halting; 00199 // so let's look up whether it was halting before and compute the overall halting time 00200 bool wasHalting = myHaltingVehicleDurations.find(veh) != myHaltingVehicleDurations.end(); 00201 if (wasHalting) { 00202 haltingVehicles[veh] = myHaltingVehicleDurations[veh] + DELTA_T; 00203 intervalHaltingVehicles[veh] = myIntervalHaltingVehicleDurations[veh] + DELTA_T; 00204 } else { 00205 haltingVehicles[veh] = DELTA_T; 00206 intervalHaltingVehicles[veh] = DELTA_T; 00207 myCurrentStartedHalts++; 00208 myStartedHalts++; 00209 } 00210 // we now check whether the halting time is large enough 00211 if (haltingVehicles[veh] > myJamHaltingTimeThreshold) { 00212 // yep --> the vehicle is a part of a jam 00213 isInJam = true; 00214 } 00215 } else { 00216 // is not standing anymore; keep duration information 00217 std::map<SUMOVehicle*, SUMOTime>::iterator v = myHaltingVehicleDurations.find(veh); 00218 if (v != myHaltingVehicleDurations.end()) { 00219 myPastStandingDurations.push_back((*v).second); 00220 myHaltingVehicleDurations.erase(v); 00221 } 00222 v = myIntervalHaltingVehicleDurations.find(veh); 00223 if (v != myIntervalHaltingVehicleDurations.end()) { 00224 myPastIntervalStandingDurations.push_back((*v).second); 00225 myIntervalHaltingVehicleDurations.erase(v); 00226 } 00227 } 00228 00229 // jam-building 00230 if (isInJam) { 00231 // the vehicle is in a jam; 00232 // it may be a new one or already an existing one 00233 if (currentJam == 0) { 00234 // the vehicle is the first vehicle in a jam 00235 currentJam = new JamInfo; 00236 currentJam->firstStandingVehicle = i; 00237 } else { 00238 // ok, we have a jam already. But - maybe it is too far away 00239 // ... honestly, I can hardly find a reason for doing this, 00240 // but jams were defined this way in an earlier version... 00241 if (veh->getPositionOnLane() - (*currentJam->lastStandingVehicle)->getPositionOnLane() > myJamDistanceThreshold) { 00242 // yep, yep, yep - it's a new one... 00243 // close the frist, build a new 00244 jams.push_back(currentJam); 00245 currentJam = new JamInfo; 00246 currentJam->firstStandingVehicle = i; 00247 } 00248 } 00249 currentJam->lastStandingVehicle = i; 00250 } else { 00251 // the vehicle is not part of a jam... 00252 // maybe we have to close an already computed jam 00253 if (currentJam != 0) { 00254 jams.push_back(currentJam); 00255 currentJam = 0; 00256 } 00257 } 00258 } 00259 if (currentJam != 0) { 00260 jams.push_back(currentJam); 00261 currentJam = 0; 00262 } 00263 00264 myCurrentMaxJamLengthInMeters = 0; 00265 myCurrentMaxJamLengthInVehicles = 0; 00266 myCurrentJamLengthInMeters = 0; 00267 myCurrentJamLengthInVehicles = 0; 00268 // process jam information 00269 for (std::vector<JamInfo*>::iterator i = jams.begin(); i != jams.end(); ++i) { 00270 // compute current jam's values 00271 SUMOReal jamLengthInMeters = 00272 (*(*i)->firstStandingVehicle)->getPositionOnLane() 00273 - (*(*i)->lastStandingVehicle)->getPositionOnLane() 00274 + (*(*i)->lastStandingVehicle)->getVehicleType().getLengthWithGap(); 00275 const MSVehicle* const occ = myLane->getPartialOccupator(); 00276 if (occ && occ == *(*i)->firstStandingVehicle && occ != *(*i)->lastStandingVehicle) { 00277 jamLengthInMeters = myLane->getPartialOccupatorEnd() + occ->getVehicleType().getLengthWithGap() 00278 - (*(*i)->lastStandingVehicle)->getPositionOnLane() 00279 + (*(*i)->lastStandingVehicle)->getVehicleType().getLengthWithGap(); 00280 } 00281 unsigned jamLengthInVehicles = (unsigned) distance((*i)->firstStandingVehicle, (*i)->lastStandingVehicle) + 1; 00282 // apply them to the statistics 00283 myCurrentMaxJamLengthInMeters = MAX2(myCurrentMaxJamLengthInMeters, jamLengthInMeters); 00284 myCurrentMaxJamLengthInVehicles = MAX2(myCurrentMaxJamLengthInVehicles, jamLengthInVehicles); 00285 myJamLengthInMetersSum += jamLengthInMeters; 00286 myJamLengthInVehiclesSum += jamLengthInVehicles; 00287 myCurrentJamLengthInMeters += jamLengthInMeters; 00288 myCurrentJamLengthInVehicles += jamLengthInVehicles; 00289 } 00290 myCurrentJamNo = (unsigned) jams.size(); 00291 00292 unsigned noVehicles = (unsigned) myKnownVehicles.size(); 00293 myVehicleSamples += noVehicles; 00294 myTimeSamples += 1; 00295 // compute occupancy values 00296 SUMOReal currentOccupancy = lengthSum / (myEndPos - myStartPos) * (SUMOReal) 100.; 00297 myCurrentOccupancy = currentOccupancy; 00298 myOccupancySum += currentOccupancy; 00299 myMaxOccupancy = MAX2(myMaxOccupancy, currentOccupancy); 00300 // compute jam values 00301 myMeanMaxJamInVehicles += myCurrentMaxJamLengthInVehicles; 00302 myMeanMaxJamInMeters += myCurrentMaxJamLengthInMeters; 00303 myMaxJamInVehicles = MAX2(myMaxJamInVehicles, myCurrentMaxJamLengthInVehicles); 00304 myMaxJamInMeters = MAX2(myMaxJamInMeters, myCurrentMaxJamLengthInMeters); 00305 // save information about halting vehicles 00306 myHaltingVehicleDurations = haltingVehicles; 00307 myIntervalHaltingVehicleDurations = intervalHaltingVehicles; 00308 // compute information about vehicle numbers 00309 myMeanVehicleNumber += (unsigned) myKnownVehicles.size(); 00310 myMaxVehicleNumber = MAX2((unsigned) myKnownVehicles.size(), myMaxVehicleNumber); 00311 // norm current values 00312 myCurrentMeanSpeed = noVehicles != 0 ? myCurrentMeanSpeed / (SUMOReal) noVehicles : -1; 00313 myCurrentMeanLength = noVehicles != 0 ? myCurrentMeanLength / (SUMOReal) noVehicles : -1; 00314 00315 // clean up 00316 for (std::vector<JamInfo*>::iterator i = jams.begin(); i != jams.end(); ++i) { 00317 delete *i; 00318 } 00319 jams.clear(); 00320 } 00321 00322 00323 00324 void 00325 MSE2Collector::writeXMLOutput(OutputDevice& dev, SUMOTime startTime, SUMOTime stopTime) { 00326 dev << " <interval begin=\"" << time2string(startTime) << "\" end=\"" << time2string(stopTime) << "\" " << "id=\"" << getID() << "\" "; 00327 00328 const SUMOReal meanSpeed = myVehicleSamples != 0 ? mySpeedSum / (SUMOReal) myVehicleSamples : -1; 00329 const SUMOReal meanOccupancy = myTimeSamples != 0 ? myOccupancySum / (SUMOReal) myTimeSamples : 0; 00330 const SUMOReal meanJamLengthInMeters = myTimeSamples != 0 ? myMeanMaxJamInMeters / (SUMOReal) myTimeSamples : 0; 00331 const SUMOReal meanJamLengthInVehicles = myTimeSamples != 0 ? myMeanMaxJamInVehicles / (SUMOReal) myTimeSamples : 0; 00332 const SUMOReal meanVehicleNumber = myTimeSamples != 0 ? (SUMOReal) myMeanVehicleNumber / (SUMOReal) myTimeSamples : 0; 00333 00334 SUMOTime haltingDurationSum = 0; 00335 SUMOTime maxHaltingDuration = 0; 00336 unsigned haltingNo = 0; 00337 for (std::vector<SUMOTime>::iterator i = myPastStandingDurations.begin(); i != myPastStandingDurations.end(); ++i) { 00338 haltingDurationSum += (*i); 00339 maxHaltingDuration = MAX2(maxHaltingDuration, (*i)); 00340 haltingNo++; 00341 } 00342 for (std::map<SUMOVehicle*, SUMOTime> ::iterator i = myHaltingVehicleDurations.begin(); i != myHaltingVehicleDurations.end(); ++i) { 00343 haltingDurationSum += (*i).second; 00344 maxHaltingDuration = MAX2(maxHaltingDuration, (*i).second); 00345 haltingNo++; 00346 } 00347 const SUMOTime meanHaltingDuration = haltingNo != 0 ? haltingDurationSum / haltingNo : 0; 00348 00349 SUMOTime intervalHaltingDurationSum = 0; 00350 SUMOTime intervalMaxHaltingDuration = 0; 00351 unsigned intervalHaltingNo = 0; 00352 for (std::vector<SUMOTime>::iterator i = myPastIntervalStandingDurations.begin(); i != myPastIntervalStandingDurations.end(); ++i) { 00353 intervalHaltingDurationSum += (*i); 00354 intervalMaxHaltingDuration = MAX2(intervalMaxHaltingDuration, (*i)); 00355 intervalHaltingNo++; 00356 } 00357 for (std::map<SUMOVehicle*, SUMOTime> ::iterator i = myIntervalHaltingVehicleDurations.begin(); i != myIntervalHaltingVehicleDurations.end(); ++i) { 00358 intervalHaltingDurationSum += (*i).second; 00359 intervalMaxHaltingDuration = MAX2(intervalMaxHaltingDuration, (*i).second); 00360 intervalHaltingNo++; 00361 } 00362 const SUMOTime intervalMeanHaltingDuration = intervalHaltingNo != 0 ? intervalHaltingDurationSum / intervalHaltingNo : 0; 00363 00364 dev << "nSamples=\"" << myVehicleSamples << "\" " 00365 << "meanSpeed=\"" << meanSpeed << "\" " 00366 << "meanOccupancy=\"" << meanOccupancy << "\" " 00367 << "maxOccupancy=\"" << myMaxOccupancy << "\" " 00368 << "meanMaxJamLengthInVehicles=\"" << meanJamLengthInVehicles << "\" " 00369 << "meanMaxJamLengthInMeters=\"" << meanJamLengthInMeters << "\" " 00370 << "maxJamLengthInVehicles=\"" << myMaxJamInVehicles << "\" " 00371 << "maxJamLengthInMeters=\"" << myMaxJamInMeters << "\" " 00372 << "jamLengthInVehiclesSum=\"" << myJamLengthInVehiclesSum << "\" " 00373 << "jamLengthInMetersSum=\"" << myJamLengthInMetersSum << "\" " 00374 << "meanHaltingDuration=\"" << STEPS2TIME(meanHaltingDuration) << "\" " 00375 << "maxHaltingDuration=\"" << STEPS2TIME(maxHaltingDuration) << "\" " 00376 << "haltingDurationSum=\"" << STEPS2TIME(haltingDurationSum) << "\" " 00377 << "meanIntervalHaltingDuration=\"" << STEPS2TIME(intervalMeanHaltingDuration) << "\" " 00378 << "maxIntervalHaltingDuration=\"" << STEPS2TIME(intervalMaxHaltingDuration) << "\" " 00379 << "intervalHaltingDurationSum=\"" << STEPS2TIME(intervalHaltingDurationSum) << "\" " 00380 << "startedHalts=\"" << myStartedHalts << "\" " 00381 << "meanVehicleNumber=\"" << meanVehicleNumber << "\" " 00382 << "maxVehicleNumber=\"" << myMaxVehicleNumber << "\" " 00383 << "/>\n"; 00384 reset(); 00385 } 00386 00387 00388 void 00389 MSE2Collector::writeXMLDetectorProlog(OutputDevice& dev) const { 00390 dev.writeXMLHeader("detector"); 00391 } 00392 00393 00394 unsigned 00395 MSE2Collector::getCurrentVehicleNumber() const { 00396 return (unsigned) myKnownVehicles.size(); 00397 } 00398 00399 00400 SUMOReal 00401 MSE2Collector::getCurrentOccupancy() const { 00402 return myCurrentOccupancy * (SUMOReal) 100.; 00403 } 00404 00405 00406 SUMOReal 00407 MSE2Collector::getCurrentMeanSpeed() const { 00408 return myCurrentMeanSpeed; 00409 } 00410 00411 00412 SUMOReal 00413 MSE2Collector::getCurrentMeanLength() const { 00414 return myCurrentMeanLength; 00415 } 00416 00417 00418 unsigned 00419 MSE2Collector::getCurrentJamNumber() const { 00420 return myCurrentJamNo; 00421 } 00422 00423 00424 unsigned 00425 MSE2Collector::getCurrentMaxJamLengthInVehicles() const { 00426 return myCurrentMaxJamLengthInVehicles; 00427 } 00428 00429 00430 SUMOReal 00431 MSE2Collector::getCurrentMaxJamLengthInMeters() const { 00432 return myCurrentMaxJamLengthInMeters; 00433 } 00434 00435 00436 unsigned 00437 MSE2Collector::getCurrentJamLengthInVehicles() const { 00438 return myCurrentJamLengthInVehicles; 00439 } 00440 00441 00442 SUMOReal 00443 MSE2Collector::getCurrentJamLengthInMeters() const { 00444 return myCurrentJamLengthInMeters; 00445 } 00446 00447 00448 unsigned 00449 MSE2Collector::getCurrentStartedHalts() const { 00450 return myCurrentStartedHalts; 00451 } 00452 00453 00454 /****************************************************************************/ 00455