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