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