bool MSCalibrator::invalidJam(int laneIndex) const { if (laneIndex < 0) { const int numLanes = (int)myEdge->getLanes().size(); for (int i = 0; i < numLanes; ++i) { if (invalidJam(i)) { return true; } } return false; } assert(laneIndex < (int)myEdge->getLanes().size()); const MSLane* const lane = myEdge->getLanes()[laneIndex]; if (lane->getVehicleNumber() < 4) { // cannot reliably detect invalid jams return false; } // maxSpeed reflects the calibration target const bool toSlow = lane->getMeanSpeed() < 0.5 * myEdge->getSpeedLimit(); return toSlow && remainingVehicleCapacity(laneIndex) < 1; }
SUMOTime METriggeredCalibrator::execute(SUMOTime currentTime) { // get current simulation values (valid for the last simulation second) // XXX could we miss vehicle movements if this is called less often than every DELTA_T (default) ? mySegment->prepareDetectorForWriting(myEdgeMeanData); // check whether an adaptation value exists if (isCurrentStateActive(currentTime)) { // all happens in isCurrentStateActive() } else { myEdgeMeanData.reset(); // discard collected values if (!mySpeedIsDefault) { // if not, reset adaptation values mySegment->getEdge().setMaxSpeed(myDefaultSpeed); MESegment* first = MSGlobals::gMesoNet->getSegmentForEdge(mySegment->getEdge()); const SUMOReal jamThresh = OptionsCont::getOptions().getFloat("meso-jam-threshold"); while (first != 0) { first->setSpeed(myDefaultSpeed, currentTime, jamThresh); first = first->getNextSegment(); } mySpeedIsDefault = true; } if (myCurrentStateInterval == myIntervals.end()) { // keep calibrator alive but do not call again return TIME2STEPS(86400); } return myFrequency; } // we are active if (!myDidSpeedAdaption && myCurrentStateInterval->v >= 0 && myCurrentStateInterval->v != mySegment->getEdge().getSpeedLimit()) { mySegment->getEdge().setMaxSpeed(myCurrentStateInterval->v); MESegment* first = MSGlobals::gMesoNet->getSegmentForEdge(mySegment->getEdge()); while (first != 0) { first->setSpeed(myCurrentStateInterval->v, currentTime, -1); first = first->getNextSegment(); } mySpeedIsDefault = false; myDidSpeedAdaption = true; } // clear invalid jams bool hadInvalidJam = false; while (invalidJam()) { hadInvalidJam = true; if (!myHaveWarnedAboutClearingJam) { WRITE_WARNING("Clearing jam at calibrator '" + myID + "' at time " + time2string(currentTime)); } // remove one vehicle currently on the segment if (mySegment->vaporizeAnyCar(currentTime)) { myClearedInJam++; } else { if (!myHaveWarnedAboutClearingJam) { // this frequenly happens for very short edges WRITE_WARNING("Could not clear jam at calibrator '" + myID + "' at time " + time2string(currentTime)); } break; } myHaveWarnedAboutClearingJam = true; } if (myCurrentStateInterval->q >= 0) { // flow calibration starts here ... // compute the number of vehicles that should have passed the calibrator within the time // rom begin of the interval const SUMOReal totalHourFraction = STEPS2TIME(myCurrentStateInterval->end - myCurrentStateInterval->begin) / (SUMOReal) 3600.; const int totalWishedNum = (int)std::floor(myCurrentStateInterval->q * totalHourFraction + 0.5); // round to closest int int adaptedNum = passed() + myClearedInJam; if (!hadInvalidJam) { // only add vehicles if we do not have an invalid upstream jam to prevent spill-back const SUMOReal hourFraction = STEPS2TIME(currentTime - myCurrentStateInterval->begin + DELTA_T) / (SUMOReal) 3600.; const int wishedNum = (int)std::floor(myCurrentStateInterval->q * hourFraction + 0.5); // round to closest int // only the difference between inflow and aspiredFlow should be added, thus // we should not count vehicles vaporized from a jam here // if we have enough time left we can add missing vehicles later const int relaxedInsertion = (int)std::floor(STEPS2TIME(myCurrentStateInterval->end - currentTime) / 3); const int insertionSlack = MAX2(0, adaptedNum + relaxedInsertion - totalWishedNum); // increase number of vehicles //std::cout << "time:" << STEPS2TIME(currentTime) << " w:" << wishedNum << " s:" << insertionSlack << " before:" << adaptedNum; while (wishedNum > adaptedNum + insertionSlack && remainingVehicleCapacity() > maximumInflow()) { SUMOVehicleParameter* pars = myCurrentStateInterval->vehicleParameter; const MSRoute* route = myProbe != 0 ? myProbe->getRoute() : 0; if (route == 0) { route = MSRoute::dictionary(pars->routeid); } if (route == 0) { WRITE_WARNING("No valid routes in calibrator '" + myID + "'."); break; } if (!route->contains(myEdge)) { WRITE_WARNING("Route '" + route->getID() + "' in calibrator '" + myID + "' does not contain edge '" + myEdge->getID() + "'."); break; } MSVehicleType* vtype = MSNet::getInstance()->getVehicleControl().getVType(pars->vtypeid); assert(route != 0 && vtype != 0); // build the vehicle const SUMOTime depart = mySegment->getNextInsertionTime(currentTime); SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars); newPars->id = myID + "." + toString(depart) + "." + toString(myInserted); newPars->depart = depart; newPars->routeid = route->getID(); MEVehicle* vehicle = static_cast<MEVehicle*>(MSNet::getInstance()->getVehicleControl().buildVehicle( newPars, route, vtype, false, false)); vehicle->setSegment(mySegment); // needed or vehicle will not be registered (XXX why?) vehicle->setEventTime(currentTime); // XXX superfluous? // move vehicle forward when the route does not begin at the calibrator's edge const MSEdge* myedge = &mySegment->getEdge(); bool atDest = false; while (vehicle->getEdge() != myedge) { // let the vehicle move to the next edge atDest = vehicle->moveRoutePointer(); } // insert vehicle into the net if (atDest || !tryEmit(mySegment, vehicle)) { //std::cout << "F "; MSNet::getInstance()->getVehicleControl().deleteVehicle(vehicle, true); break; } //std::cout << "I "; myInserted++; adaptedNum++; } } //std::cout << " after:" << adaptedNum << "\n"; // we only remove vehicles once we really have to while (totalWishedNum < adaptedNum) { if (!mySegment->vaporizeAnyCar(currentTime)) { // @bug: short edges may be jumped in a single step, giving us no chance to remove a vehicle break; } myRemoved++; adaptedNum--; } } if (myCurrentStateInterval->end <= currentTime + myFrequency) { writeXMLOutput(); } assert(!invalidJam()); return myFrequency; }
SUMOTime MSCalibrator::execute(SUMOTime currentTime) { // get current simulation values (valid for the last simulation second) // XXX could we miss vehicle movements if this is called less often than every DELTA_T (default) ? updateMeanData(); const bool hadRemovals = removePending(); // check whether an adaptation value exists if (isCurrentStateActive(currentTime)) { myAmActive = true; // all happens in isCurrentStateActive() } else { myAmActive = false; reset(); if (!mySpeedIsDefault) { // reset speed to default if (myLane == nullptr) { myEdge->setMaxSpeed(myDefaultSpeed); } else { myLane->setMaxSpeed(myDefaultSpeed); } mySpeedIsDefault = true; } if (myCurrentStateInterval == myIntervals.end()) { // keep calibrator alive for gui but do not call again return TIME2STEPS(86400); } return myFrequency; } // we are active if (!myDidSpeedAdaption && myCurrentStateInterval->v >= 0) { if (myLane == nullptr) { myEdge->setMaxSpeed(myCurrentStateInterval->v); } else { myLane->setMaxSpeed(myCurrentStateInterval->v); } mySpeedIsDefault = false; myDidSpeedAdaption = true; } const bool calibrateFlow = myCurrentStateInterval->q >= 0; const int totalWishedNum = totalWished(); int adaptedNum = passed() + myClearedInJam; #ifdef MSCalibrator_DEBUG std::cout << time2string(currentTime) << " " << myID << " q=" << myCurrentStateInterval->q << " totalWished=" << totalWishedNum << " adapted=" << adaptedNum << " jam=" << invalidJam(myLane == 0 ? -1 : myLane->getIndex()) << " entered=" << myEdgeMeanData.nVehEntered << " departed=" << myEdgeMeanData.nVehDeparted << " arrived=" << myEdgeMeanData.nVehArrived << " left=" << myEdgeMeanData.nVehLeft << " waitSecs=" << myEdgeMeanData.waitSeconds << " vaporized=" << myEdgeMeanData.nVehVaporized << "\n"; #endif if (calibrateFlow && adaptedNum < totalWishedNum && !hadRemovals) { // we need to insert some vehicles const double hourFraction = STEPS2TIME(currentTime - myCurrentStateInterval->begin + DELTA_T) / (double) 3600.; const int wishedNum = (int)std::floor(myCurrentStateInterval->q * hourFraction + 0.5); // round to closest int // only the difference between inflow and aspiredFlow should be added, thus // we should not count vehicles vaporized from a jam here // if we have enough time left we can add missing vehicles later const int relaxedInsertion = (int)std::floor(STEPS2TIME(myCurrentStateInterval->end - currentTime) / 3); const int insertionSlack = MAX2(0, adaptedNum + relaxedInsertion - totalWishedNum); // increase number of vehicles #ifdef MSCalibrator_DEBUG std::cout << " wished:" << wishedNum << " slack:" << insertionSlack << " before:" << adaptedNum << "\n"; #endif while (wishedNum > adaptedNum + insertionSlack) { SUMOVehicleParameter* pars = myCurrentStateInterval->vehicleParameter; const MSRoute* route = myProbe != nullptr ? myProbe->getRoute() : nullptr; if (route == nullptr) { route = MSRoute::dictionary(pars->routeid); } if (route == nullptr) { WRITE_WARNING("No valid routes in calibrator '" + myID + "'."); break; } if (!route->contains(myEdge)) { WRITE_WARNING("Route '" + route->getID() + "' in calibrator '" + myID + "' does not contain edge '" + myEdge->getID() + "'."); break; } const int routeIndex = (int)std::distance(route->begin(), std::find(route->begin(), route->end(), myEdge)); MSVehicleType* vtype = MSNet::getInstance()->getVehicleControl().getVType(pars->vtypeid); assert(route != 0 && vtype != 0); // build the vehicle SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars); newPars->id = myID + "." + toString((int)STEPS2TIME(myCurrentStateInterval->begin)) + "." + toString(myInserted); newPars->depart = currentTime; newPars->routeid = route->getID(); MSVehicle* vehicle; try { vehicle = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().buildVehicle( newPars, route, vtype, true, false)); } catch (const ProcessError& e) { if (!MSGlobals::gCheckRoutes) { WRITE_WARNING(e.what()); vehicle = nullptr; break; } else { throw e; } } #ifdef MSCalibrator_DEBUG std::cout << " resetting route pos: " << routeIndex << "\n"; #endif vehicle->resetRoutePosition(routeIndex); if (myEdge->insertVehicle(*vehicle, currentTime)) { if (!MSNet::getInstance()->getVehicleControl().addVehicle(vehicle->getID(), vehicle)) { throw ProcessError("Emission of vehicle '" + vehicle->getID() + "' in calibrator '" + getID() + "'failed!"); } myInserted++; adaptedNum++; #ifdef MSCalibrator_DEBUG std::cout << "I "; #endif } else { // could not insert vehicle #ifdef MSCalibrator_DEBUG std::cout << "F "; #endif MSNet::getInstance()->getVehicleControl().deleteVehicle(vehicle, true); break; } } } if (myCurrentStateInterval->end <= currentTime + myFrequency) { writeXMLOutput(); } return myFrequency; }