LCOV - code coverage report
Current view: top level - src/microsim/trigger - MSCalibrator.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 316 351 90.0 %
Date: 2024-05-06 15:32:35 Functions: 23 25 92.0 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2005-2024 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    MSCalibrator.cpp
      15             : /// @author  Daniel Krajzewicz
      16             : /// @author  Jakob Erdmann
      17             : /// @author  Michael Behrisch
      18             : /// @date    Tue, May 2005
      19             : ///
      20             : // Calibrates the flow on an edge by removing an inserting vehicles
      21             : /****************************************************************************/
      22             : #include <config.h>
      23             : 
      24             : #include <string>
      25             : #include <algorithm>
      26             : #include <cmath>
      27             : #include <microsim/MSNet.h>
      28             : #include <microsim/MSEdge.h>
      29             : #include <microsim/MSLane.h>
      30             : #include <microsim/MSEventControl.h>
      31             : #include <microsim/MSVehicleControl.h>
      32             : #include <microsim/output/MSRouteProbe.h>
      33             : #include <utils/xml/SUMOXMLDefinitions.h>
      34             : #include <utils/common/ToString.h>
      35             : #include <utils/common/UtilExceptions.h>
      36             : #include <utils/common/StringTokenizer.h>
      37             : #include <utils/xml/XMLSubSys.h>
      38             : #include <utils/common/StringUtils.h>
      39             : #include <utils/options/OptionsCont.h>
      40             : #include <utils/vehicle/SUMOVehicleParserHelper.h>
      41             : #include <utils/distribution/RandomDistributor.h>
      42             : #include <utils/vehicle/SUMOVehicleParameter.h>
      43             : #include "MSCalibrator.h"
      44             : 
      45             : //#define MSCalibrator_DEBUG
      46             : 
      47             : #define DEBUGID ""
      48             : #define DEBUGCOND (getID() == DEBUGID)
      49             : #define DEBUGCOND2(id) ((id) == DEBUGID)
      50             : 
      51             : // ===========================================================================
      52             : // static members
      53             : // ===========================================================================
      54             : std::vector<MSMoveReminder*> MSCalibrator::myLeftoverReminders;
      55             : std::vector<SUMOVehicleParameter*> MSCalibrator::myLeftoverVehicleParameters;
      56             : std::map<std::string, MSCalibrator*> MSCalibrator::myInstances;
      57             : 
      58             : // ===========================================================================
      59             : // CalibratorCommand method definitions
      60             : // ===========================================================================
      61             : 
      62             : SUMOTime
      63           6 : MSCalibrator::CalibratorCommand::shiftTime(SUMOTime currentTime, SUMOTime execTime, SUMOTime newTime) {
      64             :     UNUSED_PARAMETER(currentTime);
      65             :     UNUSED_PARAMETER(execTime);
      66             :     UNUSED_PARAMETER(newTime);
      67           6 :     myCalibrator->myCurrentStateInterval = myCalibrator->myIntervals.begin();
      68           6 :     return 0;
      69             : }
      70             : 
      71             : 
      72             : // ===========================================================================
      73             : // method definitions
      74             : // ===========================================================================
      75         477 : MSCalibrator::MSCalibrator(const std::string& id,
      76             :                            const MSEdge* const edge,
      77             :                            MSLane* lane,
      78             :                            const double pos,
      79             :                            const std::string& aXMLFilename,
      80             :                            const std::string& outputFilename,
      81             :                            const SUMOTime freq, const double length,
      82             :                            const MSRouteProbe* probe,
      83             :                            const double invalidJamThreshold,
      84             :                            const std::string& vTypes,
      85         477 :                            bool addLaneMeanData) :
      86             :     MSRouteHandler(aXMLFilename, true),
      87             :     MSDetectorFileOutput(id, vTypes, "", (int)PersonMode::NONE), // detecting persons not yet supported
      88         477 :     myEdge(const_cast<MSEdge*>(edge)),
      89         477 :     myLane(lane),
      90         477 :     myPos(pos), myProbe(probe),
      91         954 :     myMeanDataParent(id + "_dummyMeanData", 0, 0, false, false, false, false, false, false, 1, 0, 0, vTypes, "",
      92         477 :                      std::vector<MSEdge*>(), false),
      93         477 :     myEdgeMeanData(nullptr, length, false, &myMeanDataParent),
      94             :     myCurrentStateInterval(myIntervals.begin()),
      95         477 :     myOutput(nullptr), myFrequency(freq), myRemoved(0),
      96         477 :     myInserted(0),
      97         477 :     myClearedInJam(0),
      98         477 :     mySpeedIsDefault(true), myDidSpeedAdaption(false), myDidInit(false),
      99         477 :     myDefaultSpeed(myLane == nullptr ? myEdge->getSpeedLimit() : myLane->getSpeedLimit()),
     100         477 :     myHaveWarnedAboutClearingJam(false),
     101         477 :     myAmActive(false),
     102         477 :     myInvalidJamThreshold(invalidJamThreshold),
     103        1431 :     myHaveInvalidJam(false) {
     104         477 :     myInstances[id] = this;
     105         477 :     if (outputFilename != "") {
     106         269 :         myOutput = &OutputDevice::getDevice(outputFilename);
     107         269 :         writeXMLDetectorProlog(*myOutput);
     108             :     }
     109         477 :     if (aXMLFilename != "") {
     110          42 :         XMLSubSys::runParser(*this, aXMLFilename);
     111          42 :         if (!myDidInit) {
     112           0 :             init();
     113             :         }
     114             :     }
     115         477 :     if (addLaneMeanData) {
     116             :         // disabled for METriggeredCalibrator
     117        1215 :         for (MSLane* const eLane : myEdge->getLanes()) {
     118         814 :             if (myLane == nullptr || myLane == eLane) {
     119             :                 //std::cout << " cali=" << getID() << " myLane=" << Named::getIDSecure(myLane) << " checkLane=" << i << "\n";
     120         543 :                 MSMeanData_Net::MSLaneMeanDataValues* laneData = new MSMeanData_Net::MSLaneMeanDataValues(eLane, eLane->getLength(), true, &myMeanDataParent);
     121         543 :                 laneData->setDescription("meandata_calibrator_" + eLane->getID());
     122         543 :                 myLeftoverReminders.push_back(laneData);
     123         543 :                 myLaneMeanData.push_back(laneData);
     124         543 :                 VehicleRemover* remover = new VehicleRemover(eLane, this);
     125         543 :                 myLeftoverReminders.push_back(remover);
     126         543 :                 myVehicleRemovers.push_back(remover);
     127             :             }
     128             :         }
     129             :     }
     130         477 : }
     131             : 
     132             : 
     133             : void
     134         477 : MSCalibrator::init() {
     135         477 :     if (myIntervals.size() > 0) {
     136         335 :         if (myIntervals.back().end == -1) {
     137           7 :             myIntervals.back().end = SUMOTime_MAX;
     138             :         }
     139             :         // calibration should happen after regular insertions have taken place
     140         335 :         MSNet::getInstance()->getEndOfTimestepEvents()->addEvent(new CalibratorCommand(this));
     141             :     } else {
     142         433 :         WRITE_WARNINGF(TL("No flow intervals in calibrator '%'."), getID());
     143             :     }
     144         477 :     myDidInit = true;
     145         477 : }
     146             : 
     147             : 
     148         878 : MSCalibrator::~MSCalibrator() {
     149         477 :     if (myCurrentStateInterval != myIntervals.end()) {
     150          76 :         intervalEnd();
     151             :     }
     152        1020 :     for (VehicleRemover* const remover : myVehicleRemovers) {
     153             :         remover->disable();
     154             :     }
     155             :     myInstances.erase(getID());
     156        1355 : }
     157             : 
     158             : MSCalibrator::AspiredState
     159          90 : MSCalibrator::getCurrentStateInterval() const {
     160          90 :     if (myCurrentStateInterval == myIntervals.end()) {
     161           0 :         throw ProcessError(TLF("Calibrator '%' has no active or upcoming interval", getID()));
     162             :     }
     163          90 :     return *myCurrentStateInterval;
     164             : }
     165             : 
     166             : void
     167         924 : MSCalibrator::myStartElement(int element,
     168             :                              const SUMOSAXAttributes& attrs) {
     169         924 :     if (element == SUMO_TAG_FLOW) {
     170             :         AspiredState state;
     171             :         SUMOTime lastEnd = -1;
     172             :         SUMOTime lastBegin = -1;
     173         644 :         if (myIntervals.size() > 0) {
     174         309 :             lastEnd = myIntervals.back().end;
     175         309 :             lastBegin = myIntervals.back().begin;
     176         309 :             if (lastEnd == -1) {
     177             :                 lastEnd = myIntervals.back().begin;
     178             :             }
     179             :         }
     180             :         try {
     181         644 :             bool ok = true;
     182         644 :             state.q = attrs.getOpt<double>(SUMO_ATTR_VEHSPERHOUR, nullptr, ok, -1.);
     183         644 :             state.v = attrs.getOpt<double>(SUMO_ATTR_SPEED, nullptr, ok, -1.);
     184         644 :             state.begin = attrs.getSUMOTimeReporting(SUMO_ATTR_BEGIN, getID().c_str(), ok);
     185         644 :             if (state.begin < lastEnd) {
     186          24 :                 WRITE_ERRORF("Overlapping or unsorted intervals in calibrator '%' (end=%, begin2=%).", getID(), time2string(lastEnd), time2string(state.begin));
     187         636 :             } else if (state.begin <= lastBegin) {
     188          21 :                 WRITE_ERRORF("Overlapping or unsorted intervals in calibrator '%' (begin=%, begin2=%).", getID(), time2string(lastBegin), time2string(state.begin));
     189             :             }
     190         644 :             state.end = attrs.getOptSUMOTimeReporting(SUMO_ATTR_END, getID().c_str(), ok, -1);
     191         644 :             state.vehicleParameter = SUMOVehicleParserHelper::parseVehicleAttributes(element, attrs, true, true, true);
     192         644 :             state.vehicleParameter->parametersSet &= ~VEHPARS_CALIBRATORSPEED_SET;
     193         644 :             myLeftoverVehicleParameters.push_back(state.vehicleParameter);
     194             :             // vehicles should be inserted with max speed unless stated otherwise
     195         644 :             if (state.vehicleParameter->departSpeedProcedure == DepartSpeedDefinition::DEFAULT) {
     196         592 :                 state.vehicleParameter->departSpeedProcedure = DepartSpeedDefinition::MAX;
     197             :             }
     198             :             // vehicles should be inserted on any lane unless stated otherwise
     199         644 :             if (state.vehicleParameter->departLaneProcedure == DepartLaneDefinition::DEFAULT) {
     200         637 :                 if (myLane == nullptr) {
     201         327 :                     state.vehicleParameter->departLaneProcedure = DepartLaneDefinition::ALLOWED_FREE;
     202             :                 } else {
     203         310 :                     state.vehicleParameter->departLaneProcedure = DepartLaneDefinition::GIVEN;
     204         310 :                     state.vehicleParameter->departLane = myLane->getIndex();
     205             :                 }
     206           7 :             } else if (myLane != nullptr && (
     207             :                            state.vehicleParameter->departLaneProcedure != DepartLaneDefinition::GIVEN
     208           0 :                            || state.vehicleParameter->departLane != myLane->getIndex())) {
     209           0 :                 WRITE_WARNINGF(TL("Insertion lane may differ from calibrator lane for calibrator '%'."), getID());
     210             :             }
     211         788 :             if (state.vehicleParameter->vtypeid != DEFAULT_VTYPE_ID &&
     212         144 :                     MSNet::getInstance()->getVehicleControl().getVType(state.vehicleParameter->vtypeid) == nullptr) {
     213           0 :                 WRITE_ERRORF(TL("Unknown vehicle type '%' in calibrator '%'."), state.vehicleParameter->vtypeid, getID());
     214             :             }
     215           0 :         } catch (EmptyData&) {
     216           0 :             WRITE_ERRORF(TL("Mandatory attribute missing in definition of calibrator '%'."), getID());
     217           0 :         } catch (NumberFormatException&) {
     218           0 :             WRITE_ERRORF(TL("Non-numeric value for numeric attribute in definition of calibrator '%'."), getID());
     219           0 :         }
     220         644 :         if (state.q < 0 && state.v < 0 && state.vehicleParameter->vtypeid == DEFAULT_VTYPE_ID) {
     221           0 :             WRITE_ERRORF(TL("Either 'vehsPerHour',  'speed' or 'type' has to be set in flow definition of calibrator '%'."), getID());
     222             :         }
     223         644 :         if (MSGlobals::gUseMesoSim && state.q < 0 && state.vehicleParameter->vtypeid != DEFAULT_VTYPE_ID) {
     224          18 :             WRITE_ERRORF(TL("Type calibration is not supported in meso for calibrator '%'."), getID());
     225             :         }
     226         644 :         if (myIntervals.size() > 0 && myIntervals.back().end == -1) {
     227           7 :             myIntervals.back().end = state.begin;
     228             :         }
     229         644 :         myIntervals.push_back(state);
     230         644 :         myCurrentStateInterval = myIntervals.begin();
     231             :     } else {
     232         280 :         MSRouteHandler::myStartElement(element, attrs);
     233             :     }
     234         924 : }
     235             : 
     236             : 
     237             : void
     238        1359 : MSCalibrator::myEndElement(int element) {
     239        1359 :     if (element == SUMO_TAG_CALIBRATOR) {
     240         477 :         if (!myDidInit) {
     241         477 :             init();
     242             :         }
     243             :         // ensure correct state of SUMORouteHandler::myElementStack
     244         477 :         callParentEnd(element);
     245         882 :     } else if (element != SUMO_TAG_FLOW) {
     246         238 :         MSRouteHandler::myEndElement(element);
     247             :     }
     248        1359 : }
     249             : 
     250             : 
     251             : void
     252         648 : MSCalibrator::intervalEnd() {
     253         648 :     if (myOutput != nullptr) {
     254         481 :         writeXMLOutput(*myOutput, myCurrentStateInterval->begin, myCurrentStateInterval->end);
     255             :     }
     256         648 :     myDidSpeedAdaption = false;
     257         648 :     myInserted = 0;
     258         648 :     myRemoved = 0;
     259         648 :     myClearedInJam = 0;
     260         648 :     myHaveWarnedAboutClearingJam = false;
     261         648 :     reset();
     262         648 : }
     263             : 
     264             : 
     265             : bool
     266      577594 : MSCalibrator::isCurrentStateActive(SUMOTime time) {
     267      578143 :     while (myCurrentStateInterval != myIntervals.end() && myCurrentStateInterval->end <= time) {
     268             :         // XXX what about skipped intervals?
     269             :         myCurrentStateInterval++;
     270             :     }
     271      577345 :     return myCurrentStateInterval != myIntervals.end() &&
     272      577594 :            myCurrentStateInterval->begin <= time && myCurrentStateInterval->end > time;
     273             : }
     274             : 
     275             : 
     276             : int
     277      522293 : MSCalibrator::totalWished() const {
     278      522293 :     if (myCurrentStateInterval != myIntervals.end()) {
     279      522293 :         const double totalHourFraction = STEPS2TIME(myCurrentStateInterval->end - myCurrentStateInterval->begin) / (double) 3600.;
     280      522293 :         return (int)std::floor(myCurrentStateInterval->q * totalHourFraction + 0.5); // round to closest int
     281             :     } else {
     282             :         return -1;
     283             :     }
     284             : }
     285             : 
     286             : 
     287             : double
     288           0 : MSCalibrator::currentFlow() const {
     289           0 :     const double totalHourFraction = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - myCurrentStateInterval->begin) / (double) 3600.;
     290           0 :     return passed() / totalHourFraction;
     291             : }
     292             : 
     293             : 
     294             : double
     295           0 : MSCalibrator::currentSpeed() const {
     296           0 :     if (myEdgeMeanData.getSamples() > 0) {
     297           0 :         return myEdgeMeanData.getTravelledDistance() / myEdgeMeanData.getSamples();
     298             :     } else {
     299             :         return -1;
     300             :     }
     301             : }
     302             : 
     303             : 
     304             : bool
     305      477410 : MSCalibrator::removePending() {
     306      477410 :     if (myToRemove.size() > 0) {
     307       17372 :         MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
     308             :         // it is not save to remove the vehicles inside
     309             :         // VehicleRemover::notifyEnter so we do it here
     310       34745 :         for (std::set<std::string>::iterator it = myToRemove.begin(); it != myToRemove.end(); ++it) {
     311       17373 :             MSVehicle* vehicle = dynamic_cast<MSVehicle*>(vc.getVehicle(*it));
     312       17373 :             if (vehicle != nullptr) {
     313             :                 MSLane* lane = vehicle->getMutableLane();
     314       17373 :                 vehicle->onRemovalFromNet(MSMoveReminder::NOTIFICATION_VAPORIZED_CALIBRATOR);
     315       17373 :                 lane->removeVehicle(vehicle, MSMoveReminder::NOTIFICATION_VAPORIZED_CALIBRATOR);
     316       17373 :                 vc.scheduleVehicleRemoval(vehicle, true);
     317             :             } else {
     318           0 :                 WRITE_WARNINGF(TL("Calibrator '%' could not remove vehicle '%' time=%."), getID(), *it, time2string(MSNet::getInstance()->getCurrentTimeStep()));
     319             :             }
     320             :         }
     321             :         myToRemove.clear();
     322       17372 :         return true;
     323             :     }
     324             :     return false;
     325             : }
     326             : 
     327             : 
     328             : SUMOTime
     329      477410 : MSCalibrator::execute(SUMOTime currentTime) {
     330      477410 :     const bool calibrateFlow = myCurrentStateInterval->q >= 0;
     331      477410 :     const bool calibrateSpeed = myCurrentStateInterval->v >= 0;
     332             :     // get current simulation values (valid for the last simulation second)
     333      716685 :     myHaveInvalidJam = (calibrateFlow || calibrateSpeed) && invalidJam(myLane == 0 ? -1 : myLane->getIndex());
     334             :     // XXX could we miss vehicle movements if this is called less often than every DELTA_T (default) ?
     335      477410 :     updateMeanData();
     336      477410 :     const bool hadRemovals = removePending();
     337             :     // check whether an adaptation value exists
     338      477410 :     if (isCurrentStateActive(currentTime)) {
     339      432062 :         myAmActive = true;
     340             :         // all happens in isCurrentStateActive()
     341             :     } else {
     342       45348 :         myAmActive = false;
     343       45348 :         reset();
     344       45348 :         if (!mySpeedIsDefault) {
     345             :             // reset speed to default
     346         100 :             if (myLane == nullptr) {
     347          51 :                 myEdge->setMaxSpeed(myDefaultSpeed);
     348             :             } else {
     349          49 :                 myLane->setMaxSpeed(myDefaultSpeed);
     350             :             }
     351         100 :             mySpeedIsDefault = true;
     352             :         }
     353       45348 :         if (myCurrentStateInterval == myIntervals.end()) {
     354             :             // keep calibrator alive for gui but do not call again
     355             :             return TIME2STEPS(86400);
     356             :         }
     357       45157 :         return myFrequency;
     358             :     }
     359             :     // we are active
     360      432062 :     if (!myDidSpeedAdaption && calibrateSpeed) {
     361         167 :         if (myLane == nullptr) {
     362          87 :             myEdge->setMaxSpeed(myCurrentStateInterval->v);
     363             :         } else {
     364          80 :             myLane->setMaxSpeed(myCurrentStateInterval->v);
     365             :         }
     366         167 :         mySpeedIsDefault = false;
     367         167 :         myDidSpeedAdaption = true;
     368             :     }
     369             : 
     370      432062 :     const int totalWishedNum = totalWished();
     371      432062 :     int adaptedNum = passed() + myClearedInJam;
     372             : #ifdef MSCalibrator_DEBUG
     373             :     if (DEBUGCOND) {
     374             :         std::cout << time2string(currentTime) << " " << getID()
     375             :                   << " q=" << myCurrentStateInterval->q
     376             :                   << " totalWished=" << totalWishedNum
     377             :                   << " adapted=" << adaptedNum
     378             :                   << " jam=" << myHaveInvalidJam
     379             :                   << " entered=" << myEdgeMeanData.nVehEntered
     380             :                   << " departed=" << myEdgeMeanData.nVehDeparted
     381             :                   << " arrived=" << myEdgeMeanData.nVehArrived
     382             :                   << " left=" << myEdgeMeanData.nVehLeft
     383             :                   << " waitSecs=" << myEdgeMeanData.waitSeconds
     384             :                   << " vaporized=" << myEdgeMeanData.nVehVaporized
     385             :                   << "\n";
     386             :     }
     387             : #endif
     388      432062 :     if (calibrateFlow && adaptedNum < totalWishedNum && !hadRemovals) {
     389             :         // we need to insert some vehicles
     390      125549 :         const double hourFraction = STEPS2TIME(currentTime - myCurrentStateInterval->begin + DELTA_T) / (double) 3600.;
     391      125549 :         const int wishedNum = (int)std::floor(myCurrentStateInterval->q * hourFraction + 0.5); // round to closest int
     392             :         // only the difference between inflow and aspiredFlow should be added, thus
     393             :         // we should not count vehicles vaporized from a jam here
     394             :         // if we have enough time left we can add missing vehicles later
     395      125549 :         const int relaxedInsertion = (int)std::floor(STEPS2TIME(myCurrentStateInterval->end - currentTime) / 3);
     396      125549 :         const int insertionSlack = MAX2(0, adaptedNum + relaxedInsertion - totalWishedNum);
     397             :         // increase number of vehicles
     398             : #ifdef MSCalibrator_DEBUG
     399             :         if (DEBUGCOND) {
     400             :             std::cout << "   wished:" << wishedNum
     401             :                       << " slack:" << insertionSlack
     402             :                       << " before:" << adaptedNum
     403             :                       << "\n";
     404             :         }
     405             : #endif
     406      125549 :         MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
     407      155377 :         while (wishedNum > adaptedNum + insertionSlack) {
     408      103544 :             SUMOVehicleParameter* pars = myCurrentStateInterval->vehicleParameter;
     409      103544 :             ConstMSRoutePtr route = myProbe != nullptr ? myProbe->sampleRoute() : nullptr;
     410      103544 :             if (route == nullptr) {
     411      207088 :                 route = MSRoute::dictionary(pars->routeid);
     412             :             }
     413      103544 :             if (route == nullptr) {
     414           0 :                 WRITE_WARNINGF(TL("No valid routes in calibrator '%'."), getID());
     415           0 :                 break;
     416             :             }
     417      103544 :             if (!route->contains(myEdge)) {
     418           5 :                 WRITE_WARNINGF(TL("Route '%' in calibrator '%' does not contain edge '%'."), route->getID(), getID(), myEdge->getID());
     419           0 :                 break;
     420             :             }
     421      103544 :             const int routeIndex = (int)std::distance(route->begin(),
     422      103544 :                                    std::find(route->begin(), route->end(), myEdge));
     423      103544 :             MSVehicleType* vtype = vc.getVType(pars->vtypeid);
     424             :             assert(route != 0 && vtype != 0);
     425             :             // build the vehicle
     426      103544 :             const std::string newID = getNewVehicleID();
     427      103544 :             if (vc.getVehicle(newID) != nullptr) {
     428             :                 ;
     429             :                 // duplicate ids could come from loading state
     430          10 :                 myInserted++;
     431          10 :                 break;
     432             :             }
     433      103534 :             SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
     434      103534 :             newPars->id = newID;
     435      103534 :             newPars->depart = currentTime;
     436      103534 :             newPars->routeid = route->getID();
     437      103534 :             newPars->departLaneProcedure = DepartLaneDefinition::FIRST_ALLOWED; // ensure successful vehicle creation
     438             :             MSVehicle* vehicle;
     439             :             try {
     440      103534 :                 vehicle = dynamic_cast<MSVehicle*>(vc.buildVehicle(newPars, route, vtype, true, false));
     441           0 :             } catch (const ProcessError& e) {
     442           0 :                 if (!MSGlobals::gCheckRoutes) {
     443           0 :                     WRITE_WARNING(e.what());
     444             :                     vehicle = nullptr;
     445             :                     break;
     446             :                 } else {
     447           0 :                     throw e;
     448             :                 }
     449           0 :             }
     450             : #ifdef MSCalibrator_DEBUG
     451             :             if (DEBUGCOND) {
     452             :                 std::cout << " resetting route pos: " << routeIndex << "\n";
     453             :             }
     454             : #endif
     455      103534 :             vehicle->resetRoutePosition(routeIndex, pars->departLaneProcedure);
     456             :             bool success = false;
     457             :             try {
     458      103534 :                 success = myEdge->insertVehicle(*vehicle, currentTime);
     459           5 :             } catch (const ProcessError& e) {
     460           5 :                 MSNet::getInstance()->getVehicleControl().deleteVehicle(vehicle, true);
     461          10 :                 throw e;
     462           5 :             }
     463      103529 :             if (success) {
     464       29828 :                 if (!MSNet::getInstance()->getVehicleControl().addVehicle(vehicle->getID(), vehicle)) {
     465           0 :                     throw ProcessError("Emission of vehicle '" + vehicle->getID() + "' in calibrator '" + getID() + "'failed!");
     466             :                 }
     467       29828 :                 myInserted++;
     468       29828 :                 adaptedNum++;
     469             : #ifdef MSCalibrator_DEBUG
     470             :                 if (DEBUGCOND) {
     471             :                     std::cout << "I ";
     472             :                 }
     473             : #endif
     474             :             } else {
     475             :                 // could not insert vehicle
     476             : #ifdef MSCalibrator_DEBUG
     477             :                 if (DEBUGCOND) {
     478             :                     std::cout << "F ";
     479             :                 }
     480             : #endif
     481       73701 :                 MSNet::getInstance()->getVehicleControl().deleteVehicle(vehicle, true);
     482             :                 break;
     483             :             }
     484             :         }
     485             :     }
     486      432057 :     if (myCurrentStateInterval->end <= currentTime + myFrequency) {
     487         421 :         intervalEnd();
     488             :     }
     489      432057 :     return myFrequency;
     490             : }
     491             : 
     492             : void
     493       45845 : MSCalibrator::reset() {
     494       45845 :     myEdgeMeanData.reset();
     495      106927 :     for (MSMeanData_Net::MSLaneMeanDataValues* const val : myLaneMeanData) {
     496       61082 :         val->reset();
     497             :     }
     498       45845 : }
     499             : 
     500             : 
     501             : bool
     502      326631 : MSCalibrator::invalidJam(int laneIndex) const {
     503      326631 :     if (laneIndex < 0) {
     504       29367 :         const int numLanes = (int)myEdge->getLanes().size();
     505       87036 :         for (int i = 0; i < numLanes; ++i) {
     506       57989 :             if (invalidJam(i)) {
     507             :                 return true;
     508             :             }
     509             :         }
     510             :         return false;
     511             :     }
     512             :     assert(laneIndex < (int)myEdge->getLanes().size());
     513      297264 :     const MSLane* const lane = myEdge->getLanes()[laneIndex];
     514      297264 :     if (lane->getVehicleNumber() < 4) {
     515             :         // cannot reliably detect invalid jams
     516             :         return false;
     517             :     }
     518             :     // maxSpeed reflects the calibration target
     519      210726 :     const bool toSlow = lane->getMeanSpeed() < myInvalidJamThreshold * myEdge->getSpeedLimit();
     520      210726 :     return toSlow && remainingVehicleCapacity(laneIndex) < 1;
     521             : }
     522             : 
     523             : 
     524             : int
     525       54338 : MSCalibrator::remainingVehicleCapacity(int laneIndex) const {
     526       54338 :     if (laneIndex < 0) {
     527           0 :         const int numLanes = (int)myEdge->getLanes().size();
     528             :         int result = 0;
     529           0 :         for (int i = 0; i < numLanes; ++i) {
     530           0 :             result = MAX2(result, remainingVehicleCapacity(i));
     531             :         }
     532           0 :         return result;
     533             :     }
     534             :     assert(laneIndex < (int)myEdge->getLanes().size());
     535       54338 :     MSLane* lane = myEdge->getLanes()[laneIndex];
     536       54338 :     MSVehicle* last = lane->getLastFullVehicle();
     537       54338 :     const SUMOVehicleParameter* pars = myCurrentStateInterval->vehicleParameter;
     538       54338 :     const MSVehicleType* vtype = MSNet::getInstance()->getVehicleControl().getVType(pars->vtypeid);
     539       54338 :     const double spacePerVehicle = vtype->getLengthWithGap() + myEdge->getSpeedLimit() * vtype->getCarFollowModel().getHeadwayTime();
     540       54338 :     int overallSpaceLeft = (int)ceil(lane->getLength() / spacePerVehicle) - lane->getVehicleNumber();
     541       54338 :     if (last != nullptr) {
     542       54338 :         int entrySpaceLeft = (int)(last->getPositionOnLane() / spacePerVehicle);
     543       54338 :         return MAX2(overallSpaceLeft, entrySpaceLeft);
     544             :     } else {
     545             :         return overallSpaceLeft;
     546             :     }
     547             : }
     548             : 
     549             : 
     550             : void
     551       35190 : MSCalibrator::cleanup() {
     552       70857 :     while (!myInstances.empty()) {
     553         477 :         delete myInstances.begin()->second;
     554             :     }
     555       36276 :     for (MSMoveReminder* rem : myLeftoverReminders) {
     556        1086 :         delete rem;
     557             :     }
     558             :     myLeftoverReminders.clear();
     559       35834 :     for (SUMOVehicleParameter* par : myLeftoverVehicleParameters) {
     560         644 :         delete par;
     561             :     }
     562             :     myLeftoverVehicleParameters.clear();
     563       35190 : }
     564             : 
     565             : 
     566             : void
     567      568003 : MSCalibrator::updateMeanData() {
     568      568003 :     myEdgeMeanData.reset();
     569      568003 :     for (std::vector<MSMeanData_Net::MSLaneMeanDataValues*>::iterator it = myLaneMeanData.begin();
     570     1171334 :             it != myLaneMeanData.end(); ++it) {
     571      603331 :         (*it)->addTo(myEdgeMeanData);
     572             :     }
     573      568003 : }
     574             : 
     575             : 
     576             : bool
     577      133713 : MSCalibrator::VehicleRemover::notifyEnter(SUMOTrafficObject& veh, Notification /* reason */, const MSLane* /* enteredLane */) {
     578      133713 :     if (myParent == nullptr) {
     579             :         return false;
     580             :     }
     581      133713 :     if (!myParent->vehicleApplies(veh)) {
     582             :         return false;
     583             :     }
     584      129249 :     if (myParent->isActive()) {
     585       90231 :         myParent->updateMeanData();
     586       90231 :         const bool calibrateFlow = myParent->myCurrentStateInterval->q >= 0;
     587       90231 :         const int totalWishedNum = myParent->totalWished();
     588       90231 :         int adaptedNum = myParent->passed() + myParent->myClearedInJam;
     589       90231 :         if (calibrateFlow && adaptedNum > totalWishedNum) {
     590             : #ifdef MSCalibrator_DEBUG
     591             :             if (DEBUGCOND2(myParent->getID())) std::cout << time2string(MSNet::getInstance()->getCurrentTimeStep()) << " " << myParent->getID()
     592             :                         << " vaporizing " << vehicle->getID() << " to reduce flow\n";
     593             : #endif
     594        3646 :             if (myParent->scheduleRemoval(&veh)) {
     595        3646 :                 myParent->myRemoved++;
     596             :             }
     597       86585 :         } else if (myParent->myHaveInvalidJam) {
     598             : #ifdef MSCalibrator_DEBUG
     599             :             if (DEBUGCOND2(myParent->getID())) std::cout << time2string(MSNet::getInstance()->getCurrentTimeStep()) << " " << myParent->getID()
     600             :                         << " vaporizing " << vehicle->getID() << " to clear jam\n";
     601             : #endif
     602       13742 :             if (!myParent->myHaveWarnedAboutClearingJam) {
     603          96 :                 WRITE_WARNINGF(TL("Clearing jam at calibrator '%' at time=%."), myParent->getID(), time2string(SIMSTEP));
     604          32 :                 myParent->myHaveWarnedAboutClearingJam = true;
     605             :             }
     606       13742 :             if (myParent->scheduleRemoval(&veh)) {
     607       13727 :                 myParent->myClearedInJam++;
     608             :             }
     609             :         }
     610       90231 :         const std::string typeID = myParent->myCurrentStateInterval->vehicleParameter->vtypeid;
     611       90231 :         if (!calibrateFlow && typeID != DEFAULT_VTYPE_ID) {
     612             :             // calibrate type
     613       14147 :             const std::string origType = veh.getParameter().vtypeid; // could by id of vTypeDistribution
     614       14147 :             const MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
     615       14147 :             const RandomDistributor<MSVehicleType*>* oldDist = vc.getVTypeDistribution(origType);
     616       14147 :             const RandomDistributor<MSVehicleType*>* newDist = vc.getVTypeDistribution(typeID);
     617             :             bool matchDistribution = false;
     618       14147 :             if (oldDist != nullptr && newDist != nullptr &&  oldDist->getVals().size() == newDist->getVals().size()) {
     619         280 :                 auto it = std::find(oldDist->getVals().begin(), oldDist->getVals().end(), &veh.getVehicleType());
     620         280 :                 if (it != oldDist->getVals().end()) {
     621             :                     matchDistribution = true;
     622         280 :                     const int distIndex = (int)(it - oldDist->getVals().begin());
     623         280 :                     veh.replaceVehicleType(newDist->getVals()[distIndex]);
     624             :                 }
     625             :             }
     626             :             if (!matchDistribution) {
     627       13867 :                 MSVehicleType* vehicleType = MSNet::getInstance()->getVehicleControl().getVType(typeID);
     628       13867 :                 if (vehicleType == nullptr) {
     629           0 :                     throw ProcessError("Unknown vehicle type '" + typeID + "' in calibrator '" + myParent->getID() + "'");
     630             :                 }
     631       13867 :                 veh.replaceVehicleType(vehicleType);
     632             :             }
     633             :         }
     634             :     }
     635             :     return true;
     636             : }
     637             : 
     638             : 
     639             : void
     640         481 : MSCalibrator::writeXMLOutput(OutputDevice& dev, SUMOTime startTime, SUMOTime stopTime) {
     641         481 :     updateMeanData();
     642         481 :     const int p = passed();
     643             :     // meandata will be off if vehicles are removed on the next edge instead of this one
     644         481 :     const int discrepancy = myEdgeMeanData.nVehEntered + myEdgeMeanData.nVehDeparted - myEdgeMeanData.nVehVaporized - myEdgeMeanData.nVehTeleported - passed();
     645             :     //assert(discrepancy >= 0); may go negative for lane calibrator when vehicles change lane before removal
     646         481 :     const std::string ds = (discrepancy > 0 ? "\" vaporizedOnNextEdge=\"" + toString(discrepancy) : "");
     647         481 :     const double durationSeconds = STEPS2TIME(stopTime - startTime);
     648         481 :     dev.openTag(SUMO_TAG_INTERVAL);
     649         481 :     dev.writeAttr(SUMO_ATTR_BEGIN, time2string(startTime));
     650         962 :     dev.writeAttr(SUMO_ATTR_END, time2string(stopTime));
     651             :     dev.writeAttr(SUMO_ATTR_ID, getID());
     652         481 :     dev.writeAttr("nVehContrib", p);
     653         481 :     dev.writeAttr("removed", myRemoved);
     654         481 :     dev.writeAttr("inserted", myInserted);
     655         481 :     dev.writeAttr("cleared", myClearedInJam);
     656         962 :     dev.writeAttr("flow", p * 3600.0 / durationSeconds);
     657         481 :     dev.writeAttr("aspiredFlow", myCurrentStateInterval->q);
     658         481 :     dev.writeAttr(SUMO_ATTR_SPEED, myEdgeMeanData.getSamples() != 0
     659         962 :                   ? myEdgeMeanData.getTravelledDistance() / myEdgeMeanData.getSamples() : -1);
     660         481 :     dev.writeAttr("aspiredSpeed", myCurrentStateInterval->v);
     661         481 :     if (discrepancy > 0) {
     662          22 :         dev.writeAttr("vaporizedOnNextEdge", discrepancy);
     663             :     }
     664         962 :     dev.closeTag();
     665         481 : }
     666             : 
     667             : void
     668         269 : MSCalibrator::writeXMLDetectorProlog(OutputDevice& dev) const {
     669         807 :     dev.writeXMLHeader("calibratorstats", "calibratorstats_file.xsd");
     670         269 : }
     671             : 
     672             : std::string
     673      117092 : MSCalibrator::getNewVehicleID() {
     674             :     // avoid name clash for subsecond interval spacing
     675      117092 :     const double beginS = STEPS2TIME(myCurrentStateInterval->begin);
     676      117092 :     const int precision = beginS == int(beginS) ? 0 : 2;
     677      234184 :     return getID() + "." + toString(beginS, precision) + "." + toString(myInserted);
     678             : }
     679             : 
     680             : void
     681          12 : MSCalibrator::setFlow(SUMOTime begin, SUMOTime end, double vehsPerHour, double speed, SUMOVehicleParameter vehicleParameter) {
     682          12 :     auto it = myCurrentStateInterval;
     683          18 :     while (it != myIntervals.end()) {
     684          12 :         if (it->begin > begin) {
     685           0 :             throw ProcessError("Cannot set flow for calibrator '" + getID() + "' with begin time=" + time2string(begin) + " in the past.");
     686          12 :         } else if (it->begin == begin && it->end == end) {
     687             :             // update current interval
     688             :             AspiredState& state = const_cast<AspiredState&>(*it);
     689           6 :             state.q = vehsPerHour;
     690           6 :             state.v = speed;
     691           6 :             state.vehicleParameter->vtypeid = vehicleParameter.vtypeid;
     692           6 :             state.vehicleParameter->routeid = vehicleParameter.routeid;
     693           6 :             state.vehicleParameter->departLane = vehicleParameter.departLane;
     694           6 :             state.vehicleParameter->departLaneProcedure = vehicleParameter.departLaneProcedure;
     695           6 :             state.vehicleParameter->departSpeed = vehicleParameter.departSpeed;
     696           6 :             state.vehicleParameter->departSpeedProcedure = vehicleParameter.departSpeedProcedure;
     697           6 :             return;
     698           6 :         } else if (begin < it->end) {
     699           0 :             throw ProcessError(TLF("Cannot set flow for calibrator '%' with overlapping interval.", getID()));
     700           6 :         } else if (begin >= end) {
     701           0 :             throw ProcessError(TLF("Cannot set flow for calibrator '%' with negative interval.", getID()));
     702             :         }
     703             :         it++;
     704             :     }
     705             :     // add interval at the end of the known intervals
     706           6 :     const int intervalIndex = (int)(myCurrentStateInterval - myIntervals.begin());
     707             :     AspiredState state;
     708           6 :     state.begin = begin;
     709           6 :     state.end = end;
     710           6 :     state.q = vehsPerHour;
     711           6 :     state.v = speed;
     712           6 :     state.vehicleParameter = new SUMOVehicleParameter(vehicleParameter);
     713           6 :     myIntervals.push_back(state);
     714             :     // fix iterator
     715           6 :     myCurrentStateInterval = myIntervals.begin() + intervalIndex;
     716             : }
     717             : 
     718             : /****************************************************************************/

Generated by: LCOV version 1.14