LCOV - code coverage report
Current view: top level - src/microsim/devices - MSDevice_ToC.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 84.6 % 584 494
Test Date: 2024-11-22 15:46:21 Functions: 92.1 % 38 35

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2013-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    MSDevice_ToC.cpp
      15              : /// @author  Leonhard Luecken
      16              : /// @author  Daniel Krajzewicz
      17              : /// @author  Michael Behrisch
      18              : /// @author  Jakob Erdmann
      19              : /// @date    01.04.2018
      20              : ///
      21              : // The ToC Device controls the transition of control between automated and manual driving.
      22              : //
      23              : /****************************************************************************/
      24              : #include <config.h>
      25              : 
      26              : #include <algorithm>
      27              : #include <memory>
      28              : #include <utils/common/StringUtils.h>
      29              : #include <utils/options/OptionsCont.h>
      30              : #include <utils/vehicle/SUMOVehicle.h>
      31              : #include <utils/common/WrappingCommand.h>
      32              : #include <utils/common/RGBColor.h>
      33              : #include <microsim/MSNet.h>
      34              : #include <microsim/MSLane.h>
      35              : #include <microsim/MSVehicle.h>
      36              : #include <microsim/MSRouteHandler.h>
      37              : #include <microsim/MSVehicleControl.h>
      38              : #include <microsim/MSEventControl.h>
      39              : #include <microsim/MSDriverState.h>
      40              : #include <microsim/MSStoppingPlace.h>
      41              : #include <microsim/MSStop.h>
      42              : #include "MSDevice_ToC.h"
      43              : 
      44              : 
      45              : // ===========================================================================
      46              : // debug constants
      47              : // ===========================================================================
      48              : //#define DEBUG_TOC
      49              : //#define DEBUG_DYNAMIC_TOC
      50              : 
      51              : // ===========================================================================
      52              : // parameter defaults
      53              : // ===========================================================================
      54              : 
      55              : // default value for the average response time, that a driver needs to take back control
      56              : #define DEFAULT_RESPONSE_TIME -1.0
      57              : // default value for the average rate at which the driver's awareness recovers to
      58              : // 1.0 after a ToC has been performed
      59              : #define DEFAULT_RECOVERY_RATE 0.1
      60              : // Default value of the awareness below which no lane-changes are performed
      61              : #define DEFAULT_LCABSTINENCE 0.0
      62              : // The default value for the average awareness a driver has initially after a ToC
      63              : #define DEFAULT_INITIAL_AWARENESS 0.5
      64              : // The default value for the deceleration rate applied during a 'minimum risk maneuver'
      65              : #define DEFAULT_MRM_DECEL 1.5
      66              : // The default value for the dynamic ToC threshold indicates that the dynamic ToCs are deactivated
      67              : #define DEFAULT_DYNAMIC_TOC_THRESHOLD 0.0
      68              : // The default value for the probability of an MRM to occur after a dynamically triggered ToC
      69              : // (Note that these MRMs will not induce full stops in most cases)
      70              : #define DEFAULT_MRM_PROBABILITY 0.05
      71              : 
      72              : // The factor by which the dynamic ToC threshold time is multiplied to yield the lead time given for the corresponding ToC
      73              : #define DYNAMIC_TOC_LEADTIME_FACTOR 0.75
      74              : // A factor applied to the check for the dynamic ToC condition to resist aborting an ongoing dynamic ToC (and prevent oscillations)
      75              : #define DYNAMIC_TOC_ABORT_RESISTANCE_FACTOR 2.0
      76              : 
      77              : 
      78              : // The default values for the openGap parameters applied for gap creation in preparation for a ToC
      79              : #define DEFAULT_OPENGAP_TIMEGAP -1.0
      80              : #define DEFAULT_OPENGAP_SPACING 0.0
      81              : #define DEFAULT_OPENGAP_CHANGERATE 1.0
      82              : #define DEFAULT_OPENGAP_MAXDECEL 1.0
      83              : 
      84              : 
      85              : // Maximal tries to sample a positive value from the gaussian distribution
      86              : // used for the driver response time when a TOR is issued. (the distribution is assumed truncated at zero)
      87              : #define MAX_RESPONSETIME_SAMPLE_TRIES 100
      88              : // Maximal variance of responsetimes (returned for pMRM outside lookup table, i.e. pMRM>0.5), see interpolateVariance()
      89              : #define MAX_RESPONSETIME_VARIANCE 10000
      90              : 
      91              : 
      92              : // ---------------------------------------------------------------------------
      93              : // static members
      94              : // ---------------------------------------------------------------------------
      95              : std::set<MSDevice_ToC*, ComparatorNumericalIdLess> MSDevice_ToC::myInstances = std::set<MSDevice_ToC*, ComparatorNumericalIdLess>();
      96              : std::set<std::string> MSDevice_ToC::createdOutputFiles;
      97              : int MSDevice_ToC::LCModeMRM = 768; // = 0b001100000000 - no autonomous changes, no speed adaptation
      98              : SumoRNG MSDevice_ToC::myResponseTimeRNG("toc");
      99              : 
     100              : 
     101              : // ===========================================================================
     102              : // method definitions
     103              : // ===========================================================================
     104              : // ---------------------------------------------------------------------------
     105              : // static initialisation methods
     106              : // ---------------------------------------------------------------------------
     107              : void
     108        43644 : MSDevice_ToC::insertOptions(OptionsCont& oc) {
     109        43644 :     oc.addOptionSubTopic("ToC Device");
     110        87288 :     insertDefaultAssignmentOptions("toc", "ToC Device", oc);
     111              : 
     112        43644 :     oc.doRegister("device.toc.manualType", new Option_String());
     113        87288 :     oc.addDescription("device.toc.manualType", "ToC Device", TL("Vehicle type for manual driving regime."));
     114        43644 :     oc.doRegister("device.toc.automatedType", new Option_String());
     115        87288 :     oc.addDescription("device.toc.automatedType", "ToC Device", TL("Vehicle type for automated driving regime."));
     116        43644 :     oc.doRegister("device.toc.responseTime", new Option_Float(DEFAULT_RESPONSE_TIME));
     117        87288 :     oc.addDescription("device.toc.responseTime", "ToC Device", TL("Average response time needed by a driver to take back control."));
     118        43644 :     oc.doRegister("device.toc.recoveryRate", new Option_Float(DEFAULT_RECOVERY_RATE));
     119        87288 :     oc.addDescription("device.toc.recoveryRate", "ToC Device", TL("Recovery rate for the driver's awareness after a ToC."));
     120        43644 :     oc.doRegister("device.toc.lcAbstinence", new Option_Float(DEFAULT_LCABSTINENCE));
     121        87288 :     oc.addDescription("device.toc.lcAbstinence", "ToC Device", TL("Attention level below which a driver restrains from performing lane changes (value in [0,1])."));
     122        43644 :     oc.doRegister("device.toc.initialAwareness", new Option_Float(DEFAULT_INITIAL_AWARENESS));
     123        87288 :     oc.addDescription("device.toc.initialAwareness", "ToC Device", TL("Average awareness a driver has initially after a ToC (value in [0,1])."));
     124        43644 :     oc.doRegister("device.toc.mrmDecel", new Option_Float(DEFAULT_MRM_DECEL));
     125        87288 :     oc.addDescription("device.toc.mrmDecel", "ToC Device", TL("Deceleration rate applied during a 'minimum risk maneuver'."));
     126        43644 :     oc.doRegister("device.toc.dynamicToCThreshold", new Option_Float(DEFAULT_DYNAMIC_TOC_THRESHOLD));
     127        87288 :     oc.addDescription("device.toc.dynamicToCThreshold", "ToC Device", TL("Time, which the vehicle requires to have ahead to continue in automated mode. The default value of 0 indicates no dynamic triggering of ToCs."));
     128        43644 :     oc.doRegister("device.toc.dynamicMRMProbability", new Option_Float(DEFAULT_MRM_PROBABILITY));
     129        87288 :     oc.addDescription("device.toc.dynamicMRMProbability", "ToC Device", TL("Probability that a dynamically triggered TOR is not answered in time."));
     130        43644 :     oc.doRegister("device.toc.mrmKeepRight", new Option_Bool(false));
     131        87288 :     oc.addDescription("device.toc.mrmKeepRight", "ToC Device", TL("If true, the vehicle tries to change to the right during an MRM."));
     132        43644 :     oc.doRegister("device.toc.mrmSafeSpot", new Option_String());
     133        87288 :     oc.addDescription("device.toc.mrmSafeSpot", "ToC Device", TL("If set, the vehicle tries to reach the given named stopping place during an MRM."));
     134        43644 :     oc.doRegister("device.toc.mrmSafeSpotDuration", new Option_Float(60.));
     135        87288 :     oc.addDescription("device.toc.mrmSafeSpotDuration", "ToC Device", TL("Duration the vehicle stays at the safe spot after an MRM."));
     136        43644 :     oc.doRegister("device.toc.maxPreparationAccel", new Option_Float(0.0));
     137        87288 :     oc.addDescription("device.toc.maxPreparationAccel", "ToC Device", TL("Maximal acceleration that may be applied during the ToC preparation phase."));
     138        43644 :     oc.doRegister("device.toc.ogNewTimeHeadway", new Option_Float(-1.0));
     139        87288 :     oc.addDescription("device.toc.ogNewTimeHeadway", "ToC Device", TL("Timegap for ToC preparation phase."));
     140        43644 :     oc.doRegister("device.toc.ogNewSpaceHeadway", new Option_Float(-1.0));
     141        87288 :     oc.addDescription("device.toc.ogNewSpaceHeadway", "ToC Device", TL("Additional spacing for ToC preparation phase."));
     142        43644 :     oc.doRegister("device.toc.ogMaxDecel", new Option_Float(-1.0));
     143        87288 :     oc.addDescription("device.toc.ogMaxDecel", "ToC Device", TL("Maximal deceleration applied for establishing increased gap in ToC preparation phase."));
     144        43644 :     oc.doRegister("device.toc.ogChangeRate", new Option_Float(-1.0));
     145        87288 :     oc.addDescription("device.toc.ogChangeRate", "ToC Device", TL("Rate of adaptation towards the increased headway during ToC preparation."));
     146        43644 :     oc.doRegister("device.toc.useColorScheme", new Option_Bool(true));
     147        87288 :     oc.addDescription("device.toc.useColorScheme", "ToC Device", TL("Whether a coloring scheme shall by applied to indicate the different ToC stages."));
     148        43644 :     oc.doRegister("device.toc.file", new Option_String());
     149        87288 :     oc.addDescription("device.toc.file", "ToC Device", TL("Switches on output by specifying an output filename."));
     150        43644 : }
     151              : 
     152              : 
     153              : void
     154      5104373 : MSDevice_ToC::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into) {
     155      5104373 :     OptionsCont& oc = OptionsCont::getOptions();
     156     10208746 :     if (equippedByDefaultAssignmentOptions(oc, "toc", v, false)) {
     157           45 :         if (MSGlobals::gUseMesoSim) {
     158            0 :             WRITE_WARNING(TL("ToC device is not supported by the mesoscopic simulation."));
     159            0 :             return;
     160              :         }
     161           90 :         const std::string manualType = v.getStringParam("device.toc.manualType", true);
     162           91 :         const std::string automatedType = v.getStringParam("device.toc.automatedType", true);
     163           47 :         const SUMOTime responseTime = TIME2STEPS(v.getFloatParam("device.toc.responseTime"));
     164           43 :         const double recoveryRate = v.getFloatParam("device.toc.recoveryRate");
     165           43 :         const double lcAbstinence = v.getFloatParam("device.toc.lcAbstinence");
     166           43 :         const double initialAwareness = v.getFloatParam("device.toc.initialAwareness");
     167           43 :         const double mrmDecel = v.getFloatParam("device.toc.mrmDecel");
     168           43 :         const bool useColoring = v.getBoolParam("device.toc.useColorScheme");
     169           88 :         const std::string file = v.getStringParam("device.toc.file");
     170           43 :         const OpenGapParams ogp = getOpenGapParams(v);
     171           43 :         const double dynamicToCThreshold = v.getFloatParam("device.toc.dynamicToCThreshold");
     172           43 :         const double dynamicMRMProbability = getDynamicMRMProbability(v);
     173           43 :         const bool mrmKeepRight = v.getBoolParam("device.toc.mrmKeepRight");
     174           88 :         const std::string mrmSafeSpot = v.getStringParam("device.toc.mrmSafeSpot");
     175           43 :         const SUMOTime mrmSafeSpotDuration = TIME2STEPS(v.getFloatParam("device.toc.mrmSafeSpotDuration"));
     176           43 :         const double maxPreparationAccel = v.getFloatParam("device.toc.maxPreparationAccel");
     177              :         // build the device
     178           43 :         MSDevice_ToC* device = new MSDevice_ToC(v, "toc_" + v.getID(), file,
     179              :                                                 manualType, automatedType, responseTime, recoveryRate,
     180              :                                                 lcAbstinence, initialAwareness, mrmDecel, dynamicToCThreshold,
     181              :                                                 dynamicMRMProbability, maxPreparationAccel, mrmKeepRight,
     182           45 :                                                 mrmSafeSpot, mrmSafeSpotDuration, useColoring, ogp);
     183           43 :         into.push_back(device);
     184              :     }
     185              : }
     186              : 
     187              : 
     188              : double
     189           43 : MSDevice_ToC::getDynamicMRMProbability(const SUMOVehicle& v) {
     190           43 :     double pMRM = v.getFloatParam("device.toc.dynamicMRMProbability");
     191           43 :     if (pMRM < 0 || pMRM > 0.5) {
     192            1 :         const double pMRMTrunc = MAX2(0.0, MIN2(0.5, pMRM));
     193            2 :         WRITE_WARNINGF(TL("Given value for ToC device parameter 'dynamicMRMProbability' (=%) is not in the admissible range [0,0.5]. Truncated to %."), toString(pMRM), toString(pMRMTrunc));
     194              :         return pMRMTrunc;
     195              :     }
     196              :     return pMRM;
     197              : }
     198              : 
     199              : 
     200              : MSDevice_ToC::OpenGapParams
     201           43 : MSDevice_ToC::getOpenGapParams(const SUMOVehicle& v) {
     202           43 :     double timegap = v.getFloatParam("device.toc.ogNewTimeHeadway");
     203           43 :     double spacing = v.getFloatParam("device.toc.ogNewSpaceHeadway");
     204           43 :     double changeRate = v.getFloatParam("device.toc.ogChangeRate");
     205           43 :     double maxDecel = v.getFloatParam("device.toc.ogMaxDecel");
     206              :     bool specifiedAny = false;
     207              : 
     208           43 :     if (changeRate == -1.0) {
     209              :         changeRate = DEFAULT_OPENGAP_CHANGERATE;
     210              :     } else {
     211              :         specifiedAny = true;
     212              :     }
     213           43 :     if (maxDecel == -1.0) {
     214              :         maxDecel = DEFAULT_OPENGAP_MAXDECEL;
     215              :     } else {
     216              :         specifiedAny = true;
     217              :     }
     218           43 :     if (specifiedAny && timegap == -1 && spacing == -1) {
     219            0 :         WRITE_ERROR(TL("If any openGap parameters for the ToC model are specified, then at least one of toc.ogNewTimeHeadway and toc.ogNewSpaceHeadway must be defined."))
     220              :     }
     221           43 :     if (timegap == -1) {
     222              :         timegap = DEFAULT_OPENGAP_TIMEGAP;
     223              :     } else {
     224              :         specifiedAny = true;
     225              :     }
     226           43 :     if (spacing == -1) {
     227              :         spacing = DEFAULT_OPENGAP_SPACING;
     228              :     } else {
     229              :         specifiedAny = true;
     230              :     }
     231              : #ifdef DEBUG_TOC
     232              :     std::cout << "Parsed openGapParams: \n"
     233              :               << "  timegap=" << timegap
     234              :               << ", spacing=" << spacing
     235              :               << ", changeRate=" << changeRate
     236              :               << ", maxDecel=" << maxDecel
     237              :               << std::endl;
     238              : #endif
     239           43 :     return OpenGapParams(timegap, spacing, changeRate, maxDecel, specifiedAny);
     240              : }
     241              : 
     242              : // ---------------------------------------------------------------------------
     243              : // MSDevice_ToC-methods
     244              : // ---------------------------------------------------------------------------
     245           43 : MSDevice_ToC::MSDevice_ToC(SUMOVehicle& holder, const std::string& id, const std::string& outputFilename,
     246              :                            const std::string& manualType, const std::string& automatedType, SUMOTime responseTime, double recoveryRate,
     247              :                            double lcAbstinence, double initialAwareness, double mrmDecel,
     248              :                            double dynamicToCThreshold, double dynamicMRMProbability, double maxPreparationAccel,
     249           43 :                            bool mrmKeepRight, const std::string& mrmSafeSpot, SUMOTime mrmSafeSpotDuration, bool useColorScheme, OpenGapParams ogp) :
     250              :     MSVehicleDevice(holder, id),
     251           43 :     myManualTypeID(manualType),
     252           43 :     myAutomatedTypeID(automatedType),
     253           43 :     myResponseTime(responseTime),
     254           43 :     myRecoveryRate(recoveryRate),
     255           43 :     myLCAbstinence(lcAbstinence),
     256           43 :     myInitialAwareness(initialAwareness),
     257           43 :     myMRMDecel(mrmDecel),
     258           43 :     myCurrentAwareness(1.),
     259           43 :     myUseColorScheme(useColorScheme),
     260           43 :     myTriggerMRMCommand(nullptr),
     261           43 :     myTriggerToCCommand(nullptr),
     262           43 :     myRecoverAwarenessCommand(nullptr),
     263           43 :     myExecuteMRMCommand(nullptr),
     264           43 :     myPrepareToCCommand(nullptr),
     265           43 :     myOutputFile(nullptr),
     266              :     myEvents(),
     267              :     myEventLanes(),
     268              :     myEventXY(),
     269           43 :     myPreviousLCMode(-1),
     270           43 :     myOpenGapParams(ogp),
     271           43 :     myDynamicToCThreshold(dynamicToCThreshold),
     272           43 :     myMRMProbability(dynamicMRMProbability),
     273           43 :     myDynamicToCActive(dynamicToCThreshold > 0),
     274           43 :     myIssuedDynamicToC(false),
     275           43 :     myDynamicToCLane(-1),
     276           43 :     myMRMKeepRight(mrmKeepRight),
     277           43 :     myMRMSafeSpot(mrmSafeSpot),
     278           43 :     myMRMSafeSpotDuration(mrmSafeSpotDuration),
     279           43 :     myMaxPreparationAccel(maxPreparationAccel),
     280           43 :     myOriginalMaxAccel(-1) {
     281              :     // Take care! Holder is currently being constructed. Cast occurs before completion.
     282           43 :     myHolderMS = static_cast<MSVehicle*>(&holder);
     283              : 
     284           43 :     if (outputFilename != "") {
     285           35 :         myOutputFile = &OutputDevice::getDevice(outputFilename);
     286              :         // TODO: make xsd, include header
     287              :         // myOutputFile.writeXMLHeader("ToCDeviceLog", "ToCDeviceLog.xsd");
     288              :         if (createdOutputFiles.count(outputFilename) == 0) {
     289           68 :             myOutputFile->writeXMLHeader("ToCDeviceLog", "");
     290              :             createdOutputFiles.insert(outputFilename);
     291              :         }
     292              :     }
     293              : 
     294              :     // Check if the given vTypes for the ToC Device are vTypeDistributions
     295           43 :     MSVehicleControl& vehCtrl = MSNet::getInstance()->getVehicleControl();
     296           43 :     const bool automatedVTypeIsDist = vehCtrl.hasVTypeDistribution(myAutomatedTypeID);
     297           43 :     const bool manualVTypeIsDist = vehCtrl.hasVTypeDistribution(myManualTypeID);
     298              : 
     299              :     // Check if the vType of the holder matches one of the given vTypes
     300           43 :     std::string holderVTypeID = holder.getVehicleType().getID();
     301           43 :     if (holderVTypeID == myManualTypeID) {
     302            3 :         myState = ToCState::MANUAL;
     303           40 :     } else if (holderVTypeID == myAutomatedTypeID) {
     304           38 :         myState = ToCState::AUTOMATED;
     305            3 :     } else if (manualVTypeIsDist && vehCtrl.getVTypeDistributionMembership(holderVTypeID).count(myManualTypeID) > 0) {
     306              :         // Holder type id is from the given manual type distribution.
     307            0 :         myState = ToCState::MANUAL;
     308              :         myManualTypeID = holderVTypeID;
     309            3 :     } else if (automatedVTypeIsDist && vehCtrl.getVTypeDistributionMembership(holderVTypeID).count(myAutomatedTypeID) > 0) {
     310              :         // Holder type id is from the given automated type distribution.
     311            1 :         myState = ToCState::AUTOMATED;
     312              :         myAutomatedTypeID = holderVTypeID;
     313              :     } else {
     314            1 :         throw ProcessError("Vehicle type of vehicle '" + holder.getID() + "' ('" +
     315            1 :                            holder.getVehicleType().getID() + "') must coincide with manualType ('" +
     316            1 :                            manualType + "') or automatedType ('" + automatedType +
     317            2 :                            "') specified for its ToC-device (or drawn from the specified vTypeDistributions).");
     318              :     }
     319           42 :     if (!vehCtrl.hasVType(myAutomatedTypeID)) {
     320            1 :         throw ProcessError("The automated vehicle type '" + myAutomatedTypeID +
     321            2 :                            "' of vehicle '" + holder.getID() + "' is not known.");
     322              :     }
     323           41 :     if (!vehCtrl.hasVType(myManualTypeID)) {
     324            0 :         throw ProcessError("The manual vehicle type '" + myManualTypeID +
     325            0 :                            "' of vehicle '" + holder.getID() + "' is not known.");
     326              :     }
     327              : 
     328              :     // Eventually instantiate given vTypes from distributions
     329           41 :     if (myState == ToCState::MANUAL && automatedVTypeIsDist) {
     330            0 :         myAutomatedTypeID = vehCtrl.getVType(myAutomatedTypeID, MSRouteHandler::getParsingRNG())->getID();
     331           41 :     } else if (myState == ToCState::AUTOMATED && manualVTypeIsDist) {
     332            1 :         myManualTypeID = vehCtrl.getVType(myManualTypeID, MSRouteHandler::getParsingRNG())->getID();
     333              :     }
     334              : 
     335              :     // register at static instance container
     336           43 :     myInstances.insert(this);
     337           41 :     initColorScheme();
     338              : 
     339              : #ifdef DEBUG_TOC
     340              :     std::cout << "initialized device '" << id << "' with "
     341              :               << "outputFilename=" << outputFilename << ", "
     342              :               << "myManualType=" << myManualTypeID << ", "
     343              :               << "myAutomatedType=" << myAutomatedTypeID << ", "
     344              :               << "myResponseTime=" << myResponseTime << ", "
     345              :               << "myRecoveryRate=" << myRecoveryRate << ", "
     346              :               << "myInitialAwareness=" << myInitialAwareness << ", "
     347              :               << "myMRMDecel=" << myMRMDecel << ", "
     348              :               << "ogTimeHeadway=" << myOpenGapParams.newTimeHeadway << ", "
     349              :               << "ogSpaceHeadway=" << myOpenGapParams.newSpaceHeadway << ", "
     350              :               << "ogChangeRate=" << myOpenGapParams.changeRate << ", "
     351              :               << "ogMaxDecel=" << myOpenGapParams.maxDecel << ", "
     352              :               << "ogActive=" << myOpenGapParams.active << ", "
     353              :               << "myCurrentAwareness=" << myCurrentAwareness << ", "
     354              :               << "myState=" << _2string(myState) << std::endl;
     355              : #endif
     356              : 
     357              :     assert(myInitialAwareness <= 1.0 && myInitialAwareness >= 0.0);
     358           41 : }
     359              : 
     360              : 
     361              : 
     362              : void
     363           41 : MSDevice_ToC::initColorScheme() {
     364              :     //RGBColor(red, green, blue)
     365           41 :     myColorScheme[MANUAL] = MSNet::getInstance()->getVehicleControl().getVType(myManualTypeID)->getColor();
     366           41 :     myColorScheme[AUTOMATED] = MSNet::getInstance()->getVehicleControl().getVType(myAutomatedTypeID)->getColor();
     367           41 :     myColorScheme[PREPARING_TOC] = RGBColor(200, 200, 250); // light blue
     368           41 :     myColorScheme[MRM] = RGBColor(250, 50, 50); // red
     369           41 :     myColorScheme[RECOVERING] = RGBColor(250, 210, 150); // light yellow
     370           41 :     myColorScheme[UNDEFINED] = RGBColor(150, 150, 150); // gray
     371           41 : }
     372              : 
     373              : 
     374           82 : MSDevice_ToC::~MSDevice_ToC() {
     375              :     // unregister from static instance container
     376           41 :     myInstances.erase(this);
     377              :     // deschedule commands associated to this device
     378           41 :     if (myTriggerMRMCommand != nullptr) {
     379              :         myTriggerMRMCommand->deschedule();
     380              :     }
     381           41 :     if (myTriggerToCCommand != nullptr) {
     382              :         myTriggerToCCommand->deschedule();
     383              :     }
     384           41 :     if (myRecoverAwarenessCommand != nullptr) {
     385              :         myRecoverAwarenessCommand->deschedule();
     386              :     }
     387           41 :     if (myExecuteMRMCommand != nullptr) {
     388              :         myExecuteMRMCommand->deschedule();
     389            2 :         resetDeliberateLCs();
     390              :     }
     391           41 :     if (myPrepareToCCommand != nullptr) {
     392              :         myPrepareToCCommand->deschedule();
     393              :     }
     394          123 : }
     395              : 
     396              : void
     397          501 : MSDevice_ToC::setAwareness(double value) {
     398          501 :     if (value > 1.0 || value < 0.0) {
     399            0 :         std::stringstream ss;
     400            0 :         ss << "Truncating invalid value for awareness (" << value << ") to lie in [0,1].";
     401            0 :         WRITE_WARNING(ss.str());
     402              :         value = MAX2(0.0, MIN2(1.0, value));
     403            0 :     }
     404          501 :     if (myCurrentAwareness >= myLCAbstinence && value < myLCAbstinence) {
     405              :         // Awareness is now below LC abstinence level -> prevent deliberate LCs
     406            4 :         deactivateDeliberateLCs();
     407          497 :     } else if (myCurrentAwareness < myLCAbstinence && value >= myLCAbstinence) {
     408              :         // Awareness is now above LC abstinence level -> allow deliberate LCs
     409            4 :         resetDeliberateLCs();
     410              :     }
     411          501 :     myCurrentAwareness = value;
     412          501 :     myHolderMS->getDriverState()->setAwareness(value);
     413          501 : }
     414              : 
     415              : 
     416              : void
     417          255 : MSDevice_ToC::setState(ToCState state) {
     418              : #ifdef DEBUG_TOC
     419              :     std::cout << SIMTIME << " MSDevice_ToC::setState()" << std::endl;
     420              : #endif
     421          255 :     if (myState == state) {
     422              :         // No state change
     423              :         return;
     424              :     }
     425              : 
     426          255 :     if (myState == MRM) {
     427              :         // reset the vehicle's maxAccel
     428           35 :         myHolderMS->getSingularType().getCarFollowModel().setMaxAccel(myOriginalMaxAccel);
     429           35 :         resetDeliberateLCs();
     430          220 :     } else if (myState == PREPARING_TOC) {
     431           76 :         if (myOpenGapParams.active) {
     432              :             // Deactivate gap control at preparation phase end
     433            2 :             myHolderMS->getInfluencer().deactivateGapController();
     434              :         }
     435           76 :         if (state != MRM) {
     436              :             // Aborting preparation
     437           45 :             resetDeliberateLCs();
     438           45 :             myHolderMS->getSingularType().getCarFollowModel().setMaxAccel(myOriginalMaxAccel);
     439              :         }
     440          144 :     } else if (state == PREPARING_TOC || state == MRM) {
     441              : #ifdef DEBUG_TOC
     442              :         std::cout << "  Entering ToC preparation... " << std::endl;
     443              : #endif
     444              :         // Prevent lane changing during takeover preparation
     445           82 :         deactivateDeliberateLCs();
     446              :         // Store original value of maxAccel for restoring it after preparation phase
     447           82 :         myOriginalMaxAccel = myHolderMS->getCarFollowModel().getMaxAccel();
     448              :         // Impose acceleration limit during preparation
     449           82 :         myHolderMS->getSingularType().getCarFollowModel().setMaxAccel(MIN2(myMaxPreparationAccel, myOriginalMaxAccel));
     450              :     }
     451              : 
     452          255 :     if (myIssuedDynamicToC) {
     453              :         // Reset dynamic ToC flag
     454            3 :         myIssuedDynamicToC = false;
     455              :     }
     456              : 
     457          255 :     myState = state;
     458          255 :     if (myUseColorScheme) {
     459          255 :         setVehicleColor();
     460              :     }
     461              : }
     462              : 
     463              : void
     464          255 : MSDevice_ToC::setVehicleColor() {
     465          255 :     const SUMOVehicleParameter& p = myHolder.getParameter();
     466          255 :     p.color = myColorScheme[myState];
     467          255 :     p.parametersSet |= VEHPARS_COLOR_SET;
     468          255 : }
     469              : 
     470              : void
     471            8 : MSDevice_ToC::requestMRM() {
     472              :     // Remove any preparatory process
     473            8 :     descheduleToCPreparation();
     474              :     // .. and any recovery process
     475            8 :     descheduleRecovery();
     476              :     // ... and any pending ToC to manual
     477            8 :     descheduleToC();
     478              :     // Immediately trigger the MRM process
     479            8 :     triggerMRM(0);
     480            8 : }
     481              : 
     482              : 
     483              : void
     484          123 : MSDevice_ToC::requestToC(SUMOTime timeTillMRM, SUMOTime responseTime) {
     485              : #ifdef DEBUG_TOC
     486              :     std::cout << SIMTIME << " requestToC() for vehicle '" << myHolder.getID() << "', timeTillMRM=" << timeTillMRM << ", responseTime=" << responseTime << std::endl;
     487              : #endif
     488          123 :     if (myState == AUTOMATED) {
     489              :         // Initialize preparation phase
     490           76 :         if (responseTime == -1000) {
     491              :             // Sample response time from distribution
     492            4 :             const double sample = sampleResponseTime(STEPS2TIME(timeTillMRM));
     493              :             // this needs to be a separate line because TIME2STEPS may otherwise do two calls to sampleResponseTime
     494            4 :             responseTime = TIME2STEPS(sample);
     495              :         }
     496              : 
     497              :         // Schedule ToC Event
     498           76 :         myTriggerToCCommand = new WrappingCommand<MSDevice_ToC>(this, &MSDevice_ToC::triggerDownwardToC);
     499           76 :         MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(myTriggerToCCommand, SIMSTEP + responseTime);
     500              : 
     501              :         assert(myExecuteMRMCommand == nullptr);
     502              :         assert(myTriggerMRMCommand == nullptr);
     503           76 :         if (responseTime > timeTillMRM && myState != MRM) {
     504              :             // Schedule new MRM if driver response time is higher than permitted
     505           51 :             myTriggerMRMCommand = new WrappingCommand<MSDevice_ToC>(this, &MSDevice_ToC::triggerMRM);
     506           51 :             MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(myTriggerMRMCommand, SIMSTEP + timeTillMRM);
     507              :         }
     508              : 
     509              :         // Start ToC preparation process
     510           76 :         myPrepareToCCommand = new WrappingCommand<MSDevice_ToC>(this, &MSDevice_ToC::ToCPreparationStep);
     511           76 :         MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(myPrepareToCCommand, SIMSTEP + DELTA_T);
     512           76 :         setState(PREPARING_TOC);
     513           76 :         if (myOpenGapParams.active) {
     514              :             // Start gap controller
     515            2 :             double originalTau = myHolderMS->getCarFollowModel().getHeadwayTime();
     516            2 :             myHolderMS->getInfluencer().activateGapController(originalTau,
     517              :                     myOpenGapParams.newTimeHeadway, myOpenGapParams.newSpaceHeadway, -1,
     518              :                     myOpenGapParams.changeRate, myOpenGapParams.maxDecel);
     519              :         }
     520              :         // Record event
     521           76 :         if (generatesOutput()) {
     522           75 :             myEvents.push(std::make_pair(SIMSTEP, "TOR"));
     523           75 :             myEventLanes.push(std::make_pair(myHolder.getLane()->getID(), myHolder.getPositionOnLane())); // add lane and lanepos
     524           75 :             myEventXY.push(std::make_pair(myHolder.getPosition().x(), myHolder.getPosition().y()));       // add (x, y) position
     525              :         }
     526              :     } else {
     527              :         // Switch to automated mode is performed immediately
     528           47 :         if (timeTillMRM > 0) {
     529           38 :             std::stringstream ss;
     530          114 :             ss << "[t=" << SIMTIME << "] Positive transition time (" << STEPS2TIME(timeTillMRM) << "s.) for upward ToC of vehicle '" << myHolder.getID() << "' is ignored.";
     531           38 :             WRITE_WARNING(ss.str());
     532           38 :         }
     533           47 :         triggerUpwardToC(SIMSTEP + DELTA_T);
     534              :     }
     535          123 : }
     536              : 
     537              : 
     538              : SUMOTime
     539           37 : MSDevice_ToC::triggerMRM(SUMOTime /* t */) {
     540              : #ifdef DEBUG_TOC
     541              :     std::cout << SIMTIME << " triggerMRM() for vehicle '" << myHolder.getID() << "'" << std::endl;
     542              : #endif
     543              :     // Clear ongoing MRM
     544           37 :     descheduleMRM();
     545              : 
     546              :     // Start MRM process
     547           37 :     if (myMRMSafeSpot != "") {
     548            0 :         SUMOVehicleParameter::Stop stop;
     549            0 :         MSStoppingPlace* s = MSNet::getInstance()->getStoppingPlace(myMRMSafeSpot, SUMO_TAG_PARKING_AREA);
     550            0 :         if (s == nullptr) {
     551            0 :             WRITE_WARNINGF(TL("Ignoring unknown safe spot '%' for vehicle '%'."), myMRMSafeSpot, myHolder.getID());
     552              :         } else {
     553              :             stop.parkingarea = myMRMSafeSpot;
     554            0 :             stop.parking = ParkingType::OFFROAD;
     555            0 :             stop.lane = s->getLane().getID();
     556            0 :             stop.endPos = s->getEndLanePosition();
     557            0 :             stop.startPos = s->getBeginLanePosition();
     558            0 :             stop.duration = myMRMSafeSpotDuration;
     559            0 :             myHolderMS->getSingularType().setDecel(myMRMDecel);
     560              :             std::string error;
     561            0 :             if (!myHolder.addStop(stop, error)) {
     562            0 :                 WRITE_WARNING("Could not set safe spot '" + myMRMSafeSpot + "' for vehicle '" + myHolder.getID() + "'. " + error);
     563              :             }
     564              :         }
     565            0 :     } else {
     566           37 :         myExecuteMRMCommand = new WrappingCommand<MSDevice_ToC>(this, &MSDevice_ToC::MRMExecutionStep);
     567           37 :         MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(myExecuteMRMCommand, SIMSTEP + DELTA_T);
     568              :     }
     569           37 :     if (myState == MANUAL || myState == RECOVERING) {
     570            4 :         switchHolderType(myAutomatedTypeID);
     571              :     }
     572           37 :     setState(MRM);
     573           37 :     setAwareness(1.);
     574              : 
     575              :     // Record event
     576           37 :     if (generatesOutput()) {
     577           36 :         myEvents.push(std::make_pair(SIMSTEP, "MRM"));
     578           36 :         myEventLanes.push(std::make_pair(myHolder.getLane()->getID(), myHolder.getPositionOnLane())); // add lane and lanepos
     579           36 :         myEventXY.push(std::make_pair(myHolder.getPosition().x(), myHolder.getPosition().y()));       // add (x, y) position
     580              :     }
     581              : 
     582           37 :     return 0;
     583              : }
     584              : 
     585              : 
     586              : SUMOTime
     587           48 : MSDevice_ToC::triggerUpwardToC(SUMOTime /* t */) {
     588              : #ifdef DEBUG_TOC
     589              :     std::cout << SIMTIME << " triggerUpwardToC() for vehicle '" << myHolder.getID() << "'" << std::endl;
     590              : #endif
     591           48 :     descheduleToC();
     592              :     // Eventually stop ToC preparation process
     593           48 :     descheduleToCPreparation();
     594              :     // Eventually abort MRM
     595           48 :     descheduleMRM();
     596              :     // Eventually abort awareness recovery process
     597           48 :     descheduleRecovery();
     598              : 
     599           48 :     if (myState == MANUAL || myState == RECOVERING) {
     600           17 :         switchHolderType(myAutomatedTypeID);
     601              :     }
     602           48 :     setAwareness(1.);
     603           48 :     setState(AUTOMATED);
     604              : 
     605              :     // Record event
     606           48 :     if (generatesOutput()) {
     607           47 :         myEvents.push(std::make_pair(SIMSTEP, "ToCup"));
     608           47 :         myEventLanes.push(std::make_pair(myHolder.getLane()->getID(), myHolder.getPositionOnLane())); // add lane and lanepos
     609           47 :         myEventXY.push(std::make_pair(myHolder.getPosition().x(), myHolder.getPosition().y()));       // add (x, y) position
     610              :     }
     611              : 
     612           48 :     return 0;
     613              : }
     614              : 
     615              : 
     616              : SUMOTime
     617           49 : MSDevice_ToC::triggerDownwardToC(SUMOTime /* t */) {
     618              : #ifdef DEBUG_TOC
     619              :     std::cout << SIMTIME << " triggerDownwardToC() for vehicle '" << myHolder.getID() << "'" << std::endl;
     620              : #endif
     621           49 :     descheduleToC();
     622              :     // Eventually stop ToC preparation process
     623           49 :     descheduleToCPreparation();
     624              :     // Eventually abort MRM
     625           49 :     descheduleMRM();
     626              : 
     627              : #ifdef DEBUG_TOC
     628              :     std::cout << SIMTIME << " Initial awareness after ToC: " << myCurrentAwareness << std::endl;
     629              : #endif
     630              : 
     631              :     // Start awareness recovery process
     632           49 :     myRecoverAwarenessCommand = new WrappingCommand<MSDevice_ToC>(this, &MSDevice_ToC::awarenessRecoveryStep);
     633           49 :     MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(myRecoverAwarenessCommand, SIMSTEP + DELTA_T);
     634           49 :     setState(RECOVERING);
     635              : 
     636              :     // @todo: Sample initial awareness
     637           49 :     double initialAwareness = myInitialAwareness;
     638           49 :     setAwareness(initialAwareness);
     639              : 
     640           49 :     switchHolderType(myManualTypeID);
     641              : 
     642              :     // Record event
     643           49 :     if (generatesOutput()) {
     644           48 :         myEvents.push(std::make_pair(SIMSTEP, "ToCdown"));
     645           48 :         myEventLanes.push(std::make_pair(myHolder.getLane()->getID(), myHolder.getPositionOnLane())); // add lane and lanepos
     646           48 :         myEventXY.push(std::make_pair(myHolder.getPosition().x(), myHolder.getPosition().y()));       // add (x, y) position
     647              :     }
     648           49 :     return 0;
     649              : }
     650              : 
     651              : void
     652          134 : MSDevice_ToC::descheduleMRM() {
     653              :     // Eventually abort scheduled MRM
     654          134 :     if (myTriggerMRMCommand != nullptr) {
     655              :         myTriggerMRMCommand->deschedule();
     656           51 :         myTriggerMRMCommand = nullptr;
     657              :     }
     658              :     // Eventually abort ongoing MRM
     659          134 :     if (myExecuteMRMCommand != nullptr) {
     660              :         myExecuteMRMCommand->deschedule();
     661           35 :         resetDeliberateLCs();
     662           35 :         myExecuteMRMCommand = nullptr;
     663              :     }
     664          134 : }
     665              : 
     666              : 
     667              : void
     668          105 : MSDevice_ToC::descheduleToC() {
     669          105 :     if (myTriggerToCCommand != nullptr) {
     670              :         myTriggerToCCommand->deschedule();
     671           76 :         myTriggerToCCommand = nullptr;
     672              :     }
     673          105 : }
     674              : 
     675              : void
     676          134 : MSDevice_ToC::descheduleToCPreparation() {
     677              :     // Eventually stop ToC preparation process
     678          134 :     if (myPrepareToCCommand != nullptr) {
     679              :         myPrepareToCCommand->deschedule();
     680           76 :         if (myState != MRM) {
     681           47 :             resetDeliberateLCs();
     682              :         }
     683           76 :         myPrepareToCCommand = nullptr;
     684              :     }
     685          134 : }
     686              : 
     687              : void
     688           56 : MSDevice_ToC::descheduleRecovery() {
     689              :     // Eventually stop ToC preparation process
     690           56 :     if (myRecoverAwarenessCommand != nullptr) {
     691              :         myRecoverAwarenessCommand->deschedule();
     692            4 :         myRecoverAwarenessCommand = nullptr;
     693              :     }
     694           56 : }
     695              : 
     696              : 
     697              : void
     698           70 : MSDevice_ToC::switchHolderType(const std::string& targetTypeID) {
     699              : #ifdef DEBUG_TOC
     700              :     std::cout << SIMTIME << " Switching type of vehicle '" << myHolder.getID() << "' to '" << targetTypeID << "'" << std::endl;
     701              : #endif
     702           70 :     MSVehicleType* targetType = MSNet::getInstance()->getVehicleControl().getVType(targetTypeID);
     703           70 :     if (targetType == nullptr) {
     704            0 :         WRITE_ERRORF(TL("vType '%' for vehicle '%' is not known."), targetType->getID(), myHolder.getID());
     705            0 :         return;
     706              :     }
     707           70 :     myHolderMS->replaceVehicleType(targetType);
     708              : }
     709              : 
     710              : 
     711              : SUMOTime
     712          794 : MSDevice_ToC::ToCPreparationStep(SUMOTime /* t */) {
     713              : #ifdef DEBUG_TOC
     714              :     std::cout << SIMTIME << " ToC preparation step for vehicle '" << myHolder.getID() << "'" << std::endl;
     715              : #endif
     716          794 :     if (myState == PREPARING_TOC) {
     717          765 :         return DELTA_T;
     718              :     } else {
     719              : #ifdef DEBUG_TOC
     720              :         std::cout << SIMTIME << " Aborting ToC preparation for vehicle '" << myHolder.getID() << "'" << std::endl;
     721              : #endif
     722           29 :         descheduleToCPreparation();
     723           29 :         return 0;
     724              :     }
     725              : }
     726              : 
     727              : 
     728              : SUMOTime
     729         1213 : MSDevice_ToC::MRMExecutionStep(SUMOTime t) {
     730         1213 :     deactivateDeliberateLCs();
     731         1213 :     const double currentSpeed = myHolderMS->getSpeed();
     732              : #ifdef DEBUG_TOC
     733              :     std::cout << SIMTIME << " MRM step for vehicle '" << myHolder.getID() << "', currentSpeed=" << currentSpeed << std::endl;
     734              : #endif
     735              : 
     736              :     // Induce slowdown with MRMDecel
     737              :     std::vector<std::pair<SUMOTime, double> > speedTimeLine;
     738         1213 :     const double nextSpeed = MAX2(0., currentSpeed - ACCEL2SPEED(myMRMDecel));
     739         1213 :     speedTimeLine.push_back(std::make_pair(t - DELTA_T, currentSpeed));
     740         1213 :     speedTimeLine.push_back(std::make_pair(t, nextSpeed));
     741         1213 :     myHolderMS->getInfluencer().setSpeedTimeLine(speedTimeLine);
     742              : 
     743         1213 :     if (myMRMKeepRight) {
     744              :         // Try to change to the right
     745              :         std::vector<std::pair<SUMOTime, int> > laneTimeLine;
     746           34 :         laneTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep(), 0));
     747           34 :         laneTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep() + 1, 0));
     748           34 :         myHolderMS->getInfluencer().setLaneTimeLine(laneTimeLine);
     749              : //      std::cout << "Keeping right..." << std::endl;
     750           34 :     }
     751              : 
     752         1213 :     if (myState == MRM) {
     753         1213 :         return DELTA_T;
     754              :     } else {
     755              : #ifdef DEBUG_TOC
     756              :         std::cout << SIMTIME << " Aborting MRM for vehicle '" << myHolder.getID() << "'" << std::endl;
     757              : #endif
     758            0 :         resetDeliberateLCs();
     759              :         return 0;
     760              :     }
     761         1213 : }
     762              : 
     763              : 
     764              : SUMOTime
     765          367 : MSDevice_ToC::awarenessRecoveryStep(SUMOTime /* t */) {
     766              : #ifdef DEBUG_TOC
     767              :     std::cout << SIMTIME << " Awareness recovery step for vehicle '" << myHolder.getID() << "'" << std::endl;
     768              : #endif
     769              :     // Proceed with awareness recovery
     770          367 :     if (myCurrentAwareness < 1.0) {
     771          689 :         setAwareness(MIN2(1.0, myCurrentAwareness + TS * myRecoveryRate));
     772              :     }
     773              : 
     774              : #ifdef DEBUG_TOC
     775              :     std::cout << SIMTIME << " currentAwareness = " << myCurrentAwareness << std::endl;
     776              : #endif
     777              : 
     778          367 :     const bool awarenessRecoveryCompleted = myCurrentAwareness == 1.0;
     779          367 :     if (awarenessRecoveryCompleted) {
     780              : #ifdef DEBUG_TOC
     781              :         std::cout << SIMTIME << " Awareness recovery completed for veh '" << myHolder.getID() << "'" << std::endl;
     782              : #endif
     783           45 :         myRecoverAwarenessCommand->deschedule();
     784           45 :         myRecoverAwarenessCommand = nullptr;
     785           45 :         setState(MANUAL);
     786           45 :         return 0;
     787              :     }
     788          322 :     return DELTA_T;
     789              : }
     790              : 
     791              : bool
     792        15687 : MSDevice_ToC::notifyMove(SUMOTrafficObject& /*veh*/,
     793              :                          double /*oldPos*/,
     794              :                          double /*newPos*/,
     795              :                          double /*newSpeed*/) {
     796        15687 :     if (myState == AUTOMATED && checkDynamicToC()) {
     797              :         // Initiate a ToC
     798              :         // Record event
     799            3 :         if (generatesOutput()) {
     800            3 :             myEvents.push(std::make_pair(SIMSTEP, "DYNTOR"));
     801            3 :             myEventLanes.push(std::make_pair(myHolder.getLane()->getID(), myHolder.getPositionOnLane())); // add lane and lanepos
     802            3 :             myEventXY.push(std::make_pair(myHolder.getPosition().x(), myHolder.getPosition().y()));       // add (x, y) position
     803              :         }
     804              :         // Leadtime for dynamic ToC is proportional to the time assumed for the dynamic ToC threshold
     805            3 :         const double leadTime = myDynamicToCThreshold * 1000 * DYNAMIC_TOC_LEADTIME_FACTOR;
     806            3 :         requestToC((SUMOTime) leadTime);
     807              :         // TODO: Alter the response time according to the given lead time. Consider re-sampling it at each call of requestToC(). (Conditional to whether a non-negative response time was given in the configuration)
     808            3 :         myIssuedDynamicToC = true;
     809            3 :         myDynamicToCLane = myHolderMS->getLane()->getNumericalID();
     810        15684 :     } else if (myIssuedDynamicToC && myState == PREPARING_TOC && !checkDynamicToC()) {
     811              :         // Abort dynamic ToC, FIXME: This could abort an externally requested ToC in rare occasions... (needs test)
     812              :         // Record event
     813            1 :         if (generatesOutput()) {
     814            1 :             myEvents.push(std::make_pair(SIMSTEP, "DYNTOR"));
     815            1 :             myEventLanes.push(std::make_pair(myHolder.getLane()->getID(), myHolder.getPositionOnLane())); // add lane and lanepos
     816            1 :             myEventXY.push(std::make_pair(myHolder.getPosition().x(), myHolder.getPosition().y()));       // add (x, y) position
     817              :         }
     818              :         // NOTE: This should not occur if lane changing is prevented during ToC preparation...
     819              :         // TODO: Reset response time to the original value (unnecessary if re-sampling for each call to requestToC)
     820            1 :         triggerUpwardToC(0);
     821              :     }
     822        15687 :     return true;
     823              : }
     824              : 
     825              : std::string
     826        44415 : MSDevice_ToC::getParameter(const std::string& key) const {
     827        44415 :     if (key == "manualType") {
     828              :         return myManualTypeID;
     829        42585 :     } else if (key == "automatedType") {
     830              :         return myAutomatedTypeID;
     831        40755 :     } else if (key == "responseTime") {
     832         1830 :         return toString(STEPS2TIME(myResponseTime));
     833        38925 :     } else if (key == "recoveryRate") {
     834         1830 :         return toString(myRecoveryRate);
     835        37095 :     } else if (key == "initialAwareness") {
     836         1830 :         return toString(myInitialAwareness);
     837        35265 :     } else if (key == "mrmDecel") {
     838         1830 :         return toString(myMRMDecel);
     839        33435 :     } else if (key == "currentAwareness") {
     840        15545 :         return toString(myCurrentAwareness);
     841        17890 :     } else if (key == "lcAbstinence") {
     842           10 :         return toString(myLCAbstinence);
     843        17880 :     } else if (key == "state") {
     844        15799 :         return _2string(myState);
     845         2081 :     } else if (key == "holder") {
     846         1830 :         return myHolder.getID();
     847          251 :     } else if (key == "hasDynamicToC") {
     848            0 :         return toString(myDynamicToCActive);
     849          251 :     } else if (key == "dynamicToCThreshold") {
     850          216 :         return toString(myDynamicToCThreshold);
     851           35 :     } else if (key == "dynamicMRMProbability") {
     852           10 :         return toString(myMRMProbability);
     853           25 :     } else if (key == "mrmKeepRight") {
     854           10 :         return toString(myMRMKeepRight);
     855           15 :     } else if (key == "mrmSafeSpot") {
     856              :         return myMRMSafeSpot;
     857           15 :     } else if (key == "mrmSafeSpotDuration") {
     858            0 :         return toString(STEPS2TIME(myMRMSafeSpotDuration));
     859           15 :     } else if (key == "maxPreparationAccel") {
     860           10 :         return toString(myMaxPreparationAccel);
     861            5 :     } else if (key == "ogNewTimeHeadway") {
     862            1 :         return toString(myOpenGapParams.newTimeHeadway);
     863            4 :     } else if (key == "ogNewSpaceHeadway") {
     864            2 :         return toString(myOpenGapParams.newSpaceHeadway);
     865            2 :     } else if (key == "ogChangeRate") {
     866            1 :         return toString(myOpenGapParams.changeRate);
     867            1 :     } else if (key == "ogMaxDecel") {
     868            1 :         return toString(myOpenGapParams.maxDecel);
     869              :     }
     870            0 :     throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
     871              : }
     872              : 
     873              : 
     874              : void
     875          132 : MSDevice_ToC::setParameter(const std::string& key, const std::string& value) {
     876              : #ifdef DEBUG_TOC
     877              :     std::cout << SIMTIME << " MSDevice_ToC::setParameter(key=" << key << ", value=" << value << ")" << std::endl;
     878              : #endif
     879          132 :     if (key == "manualType") {
     880            0 :         myManualTypeID = value;
     881            0 :         myColorScheme[MANUAL] = MSNet::getInstance()->getVehicleControl().getVType(myManualTypeID)->getColor();
     882            0 :         if (myState == MANUAL) {
     883            0 :             switchHolderType(value);
     884              :         }
     885          132 :     } else if (key == "automatedType") {
     886            0 :         myAutomatedTypeID = value;
     887            0 :         myColorScheme[AUTOMATED] = MSNet::getInstance()->getVehicleControl().getVType(myAutomatedTypeID)->getColor();
     888            0 :         if (myState == AUTOMATED || myState == PREPARING_TOC || myState == MRM) {
     889            0 :             switchHolderType(value);
     890              :         }
     891          132 :     } else if (key == "responseTime") {
     892            0 :         myResponseTime = TIME2STEPS(StringUtils::toDouble(value));
     893          132 :     } else if (key == "recoveryRate") {
     894            0 :         myRecoveryRate = StringUtils::toDouble(value);
     895          132 :     } else if (key == "initialAwareness") {
     896            0 :         myInitialAwareness = StringUtils::toDouble(value);
     897          132 :     } else if (key == "lcAbstinence") {
     898            0 :         myLCAbstinence = StringUtils::toDouble(value);
     899            0 :         if (isManuallyDriven()) {
     900            0 :             setAwareness(myCurrentAwareness); // to eventually trigger LC-prevention
     901              :         }
     902          132 :     } else if (key == "currentAwareness") {
     903            0 :         if (isManuallyDriven()) {
     904            0 :             setAwareness(StringUtils::toDouble(value));
     905              :         } else {
     906            0 :             WRITE_WARNING(TL("Setting device.toc.currentAwareness during automated mode has no effect."))
     907              :         }
     908          132 :     } else if (key == "mrmDecel") {
     909            0 :         myMRMDecel = StringUtils::toDouble(value);
     910          132 :     } else if (key == "requestToC") {
     911              :         // setting this magic parameter gives the interface for inducing a ToC
     912          120 :         const SUMOTime timeTillMRM = TIME2STEPS(StringUtils::toDouble(value));
     913          120 :         requestToC(timeTillMRM, myResponseTime);
     914           12 :     } else if (key == "requestMRM") {
     915              :         // setting this magic parameter gives the interface for inducing an MRM
     916            8 :         requestMRM();
     917            4 :     } else if (key == "awareness") {
     918              :         // setting this magic parameter gives the interface for setting the driverstate's awareness
     919            0 :         setAwareness(StringUtils::toDouble(value));
     920            4 :     } else if (key == "dynamicToCThreshold") {
     921            0 :         const double newValue = StringUtils::toDouble(value);
     922            0 :         if (newValue < 0) {
     923            0 :             WRITE_WARNINGF(TL("Value of dynamicToCThreshold must be non-negative. (Given value % for vehicle % is ignored)"), value, myHolderMS->getID());
     924            0 :         } else if (newValue == 0) {
     925            0 :             myDynamicToCThreshold = newValue;
     926            0 :             myDynamicToCActive = false;
     927              :         } else {
     928            0 :             myDynamicToCThreshold = newValue;
     929            0 :             myDynamicToCActive = true;
     930              :         }
     931            4 :     } else if (key == "dynamicMRMProbability") {
     932            0 :         const double newValue = StringUtils::toDouble(value);
     933            0 :         if (newValue < 0) {
     934            0 :             WRITE_WARNINGF(TL("Value of dynamicMRMProbability must be non-negative. (Given value % for vehicle % is ignored)"), value, myHolderMS->getID());
     935              :         } else {
     936            0 :             myMRMProbability = newValue;
     937              :         }
     938            4 :     } else if (key == "mrmKeepRight")  {
     939            0 :         const bool newValue = StringUtils::toBool(value);
     940            0 :         myMRMKeepRight = newValue;
     941            4 :     } else if (key == "mrmSafeSpot") {
     942            0 :         myMRMSafeSpot = value;
     943            4 :     } else if (key == "mrmSafeSpotDuration") {
     944            0 :         myMRMSafeSpotDuration = TIME2STEPS(StringUtils::toDouble(value));
     945            4 :     } else if (key == "maxPreparationAccel") {
     946            0 :         const double newValue = StringUtils::toDouble(value);
     947            0 :         if (newValue < 0) {
     948            0 :             WRITE_WARNINGF(TL("Value of maxPreparationAccel must be non-negative. (Given value % for vehicle % is ignored)"), value, myHolderMS->getID());
     949              :         } else {
     950            0 :             myMaxPreparationAccel = newValue;
     951              :         }
     952            4 :     } else if (key == "ogNewTimeHeadway") {
     953            1 :         const double newValue = StringUtils::toDouble(value);
     954            1 :         myOpenGapParams.newTimeHeadway = newValue;
     955            1 :         myOpenGapParams.active = true;
     956            3 :     } else if (key == "ogNewSpaceHeadway") {
     957            1 :         const double newValue = StringUtils::toDouble(value);
     958            1 :         myOpenGapParams.newSpaceHeadway = newValue;
     959            1 :         myOpenGapParams.active = true;
     960            2 :     } else if (key == "ogChangeRate") {
     961            1 :         const double newValue = StringUtils::toDouble(value);
     962            1 :         myOpenGapParams.changeRate = newValue;
     963            1 :         myOpenGapParams.active = true;
     964            1 :     } else if (key == "ogMaxDecel") {
     965            1 :         const double newValue = StringUtils::toDouble(value);
     966            1 :         myOpenGapParams.maxDecel = newValue;
     967            1 :         myOpenGapParams.active = true;
     968              :     } else {
     969            0 :         throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
     970              :     }
     971          132 : }
     972              : 
     973              : 
     974              : MSDevice_ToC::ToCState
     975            0 : MSDevice_ToC::_2ToCState(const std::string& str) {
     976            0 :     if (str == "UNDEFINED") {
     977              :         return UNDEFINED;
     978            0 :     } else if (str == "MANUAL") {
     979              :         return MANUAL;
     980            0 :     } else if (str == "AUTOMATED") {
     981              :         return AUTOMATED;
     982            0 :     } else if (str == "PREPARING_TOC") {
     983              :         return PREPARING_TOC;
     984            0 :     } else if (str == "MRM") {
     985              :         return MRM;
     986            0 :     } else if (str == "RECOVERING") {
     987              :         return RECOVERING;
     988              :     } else {
     989            0 :         WRITE_WARNINGF(TL("Unknown ToCState '%'"), str);
     990            0 :         return UNDEFINED;
     991              :     }
     992              : }
     993              : 
     994              : 
     995              : std::string
     996        15799 : MSDevice_ToC::_2string(ToCState state) {
     997        15799 :     if (state == UNDEFINED) {
     998            0 :         return "UNDEFINED";
     999              :     } else if (state == MANUAL) {
    1000         8912 :         return "MANUAL";
    1001              :     } else if (state == AUTOMATED) {
    1002         4370 :         return "AUTOMATED";
    1003              :     } else if (state == PREPARING_TOC) {
    1004          881 :         return "PREPARING_TOC";
    1005              :     } else if (state == MRM) {
    1006         1254 :         return "MRM";
    1007              :     } else if (state == RECOVERING) {
    1008          382 :         return "RECOVERING";
    1009              :     } else {
    1010            0 :         WRITE_WARNINGF(TL("Unknown ToCState '%'"), toString(state));
    1011            0 :         return toString(state);
    1012              :     }
    1013              : }
    1014              : 
    1015              : 
    1016              : void
    1017        15513 : MSDevice_ToC::writeOutput() {
    1018        15513 :     if (!generatesOutput()) {
    1019              :         assert(myEvents.empty());
    1020              :         return;
    1021              :     }
    1022        15720 :     while (!myEvents.empty()) {
    1023              :         const std::pair<SUMOTime, std::string> e = myEvents.front(); // make a copy, it is used after pop
    1024              :         const std::pair<std::string, double>& l = myEventLanes.front();
    1025              :         const std::pair<double, double>& p = myEventXY.front();
    1026          207 :         myOutputFile->openTag(e.second);
    1027          621 :         myOutputFile->writeAttr("id", myHolder.getID()).writeAttr("t", STEPS2TIME(e.first));
    1028          621 :         myOutputFile->writeAttr("lane", l.first).writeAttr("lanePos", l.second);
    1029          621 :         myOutputFile->writeAttr("x", p.first).writeAttr("y", p.second);
    1030          414 :         myOutputFile->closeTag();
    1031              :         myEvents.pop();
    1032              :         myEventLanes.pop();
    1033              :         myEventXY.pop();
    1034              : 
    1035          207 :         if (e.second.compare("DYNTOR") == 0 && !myEvents.empty()) { // skip "TOR" events if duplicate of "DYNTOR"
    1036              :             std::pair<SUMOTime, std::string>& eNext = myEvents.front();
    1037            4 :             if (eNext.second.compare("TOR") == 0 && eNext.first == e.first) {
    1038              :                 myEvents.pop();
    1039              :                 myEventLanes.pop();
    1040              :                 myEventXY.pop();
    1041              :             }
    1042              :         }
    1043              :     }
    1044              : }
    1045              : 
    1046              : 
    1047              : void
    1048        40275 : MSDevice_ToC::cleanup() {
    1049              :     // Close xml bodies for all existing files
    1050              :     // TODO: Check if required
    1051        40308 :     for (auto& fn : createdOutputFiles) {
    1052           33 :         OutputDevice* file = &OutputDevice::getDevice(fn);
    1053           66 :         file->closeTag();
    1054              :     }
    1055        40275 : }
    1056              : 
    1057              : 
    1058              : void
    1059          168 : MSDevice_ToC::resetDeliberateLCs() {
    1060          168 :     if (myPreviousLCMode != -1) {
    1061           85 :         myHolderMS->getInfluencer().setLaneChangeMode(myPreviousLCMode);
    1062              : #ifdef DEBUG_TOC
    1063              :         std::cout << SIMTIME << " MSDevice_ToC::resetLCMode() restoring LC Mode of vehicle '" << myHolder.getID() << "' to " << myPreviousLCMode << std::endl;
    1064              : #endif
    1065              :     }
    1066          168 :     myPreviousLCMode = -1;
    1067          168 : }
    1068              : 
    1069              : 
    1070              : void
    1071         1299 : MSDevice_ToC::deactivateDeliberateLCs() {
    1072         1299 :     const int lcModeHolder = myHolderMS->getInfluencer().getLaneChangeMode();
    1073         1299 :     if (lcModeHolder != LCModeMRM) {
    1074           85 :         myPreviousLCMode = lcModeHolder;
    1075              : #ifdef DEBUG_TOC
    1076              :         std::cout << SIMTIME << " MSDevice_ToC::setLCModeMRM() setting LC Mode of vehicle '" << myHolder.getID()
    1077              :                   << "' from " << myPreviousLCMode << " to " << LCModeMRM << std::endl;
    1078              : #endif
    1079           85 :         myHolderMS->getInfluencer().setLaneChangeMode(LCModeMRM);
    1080              :     }
    1081         1299 : }
    1082              : 
    1083              : bool
    1084            0 : MSDevice_ToC::isManuallyDriven() {
    1085            0 :     return (myState == MANUAL || myState == RECOVERING);
    1086              : }
    1087              : 
    1088              : bool
    1089            0 : MSDevice_ToC::isAutomated() {
    1090            0 :     return (myState == AUTOMATED || myState == PREPARING_TOC || myState == MRM);
    1091              : }
    1092              : 
    1093              : bool
    1094         4305 : MSDevice_ToC::checkDynamicToC() {
    1095              : #ifdef DEBUG_DYNAMIC_TOC
    1096              :     std::cout << SIMTIME << " # MSDevice_ToC::checkDynamicToC() for veh '" << myHolder.getID() << "'" << std::endl;
    1097              : #endif
    1098         4305 :     if (!myDynamicToCActive) {
    1099              :         return false;
    1100              :     }
    1101              :     // The vehicle's current lane
    1102          233 :     const MSLane* currentLane = myHolderMS->getLane();
    1103              : 
    1104          233 :     if (currentLane->isInternal()) {
    1105              :         // Don't start or abort dynamic ToCs on internal lanes
    1106            1 :         return myIssuedDynamicToC;
    1107              :     }
    1108              : 
    1109          232 :     if (myIssuedDynamicToC) {
    1110              : #ifdef DEBUG_DYNAMIC_TOC
    1111              :         std::cout << SIMTIME << " Dynamic ToC is ongoing." << std::endl;
    1112              : #endif
    1113              :         // Dynamic ToC in progress. Resist to aborting it if lane was not changed.
    1114           26 :         if (myDynamicToCLane == currentLane->getNumericalID()) {
    1115              :             return true;
    1116              :         }
    1117              :     }
    1118              :     // Length for which the current route can be followed
    1119          207 :     const std::vector<MSVehicle::LaneQ>& bestLanes = myHolderMS->getBestLanes();
    1120              :     // Maximal distance for route continuation without LCs over the possible start lanes
    1121              :     double maximalContinuationDistance = 0;
    1122              :     // Distance for route continuation without LCs from the vehicle's current lane
    1123              :     double continuationDistanceOnCurrent = 0;
    1124              :     // Lane of the next stop
    1125              :     const MSLane* nextStopLane = nullptr;
    1126              : 
    1127          207 :     if (myHolderMS->hasStops()) {
    1128           79 :         nextStopLane = myHolderMS->getNextStop().lane;
    1129              :     }
    1130          528 :     for (auto& i : bestLanes) {
    1131          400 :         maximalContinuationDistance = MAX2(maximalContinuationDistance, i.length);
    1132          400 :         if (currentLane == i.lane) {
    1133          207 :             if (myHolderMS->hasStops()) {
    1134              :                 // Check if the next stop lies on the route continuation from the current lane
    1135           79 :                 for (MSLane* l : i.bestContinuations) {
    1136           79 :                     if (l == nextStopLane) {
    1137              : #ifdef DEBUG_DYNAMIC_TOC
    1138              :                         std::cout << SIMTIME << " Stop found on the route continuation from the current lane. => No ToC" << std::endl;
    1139              : #endif
    1140              :                         // Stop found on the route continuation from the current lane => no ToC necessary
    1141              :                         return false;
    1142              :                     }
    1143              :                 }
    1144              :             }
    1145          128 :             continuationDistanceOnCurrent = i.length;
    1146              :         }
    1147              :     }
    1148          128 :     if (continuationDistanceOnCurrent == maximalContinuationDistance) {
    1149              :         // There is no better lane than the current, hence no desire to change lanes,
    1150              :         // which the driver could pursue better than the automation => no reason for ToC.
    1151              :         return false;
    1152              :     }
    1153           91 :     const double distFromCurrent = continuationDistanceOnCurrent - myHolderMS->getPositionOnLane();
    1154           91 :     const double MRMDist = 0.5 * myHolderMS->getSpeed() * myHolderMS->getSpeed() / MAX2(myMRMDecel, 0.0001);
    1155           91 :     double distThreshold = myHolderMS->getSpeed() * myDynamicToCThreshold + MRMDist;
    1156              : #ifdef DEBUG_DYNAMIC_TOC
    1157              :     std::cout << "  speed=" << myHolderMS->getSpeed()
    1158              :               << ", distFromCurrent=" << distFromCurrent
    1159              :               << ", maximal dist=" << maximalContinuationDistance - myHolderMS->getPositionOnLane()
    1160              :               << ", distThreshold=" << distThreshold
    1161              :               << std::endl;
    1162              : #endif
    1163              : 
    1164           91 :     if (myIssuedDynamicToC) {
    1165              :         // In case of an ongoing ToC, add an additional resistance to abort it.
    1166              :         // (The lane-check above does not capture lanes subsequent to the dynamic ToC lane)
    1167            0 :         distThreshold *= DYNAMIC_TOC_ABORT_RESISTANCE_FACTOR;
    1168              :     }
    1169              : 
    1170           91 :     if (distFromCurrent < distThreshold) {
    1171              :         // TODO: Make this more sophisticated in dealing with low speeds/stops and route ends
    1172              : #ifdef DEBUG_DYNAMIC_TOC
    1173              :         std::cout << SIMTIME << "  * distAlongBest is below threshold! *" << std::endl;
    1174              : #endif
    1175              :         return true;
    1176              :     }
    1177              : 
    1178              :     return false;
    1179              : }
    1180              : 
    1181              : double
    1182            4 : MSDevice_ToC::sampleResponseTime(double leadTime) const {
    1183              : #ifdef DEBUG_DYNAMIC_TOC
    1184              :     std::cout << "sampleResponseTime() leadTime=" << leadTime << std::endl;
    1185              : #endif
    1186              :     const double mean = responseTimeMean(leadTime);
    1187            4 :     const double var = interpolateVariance(leadTime, myMRMProbability);
    1188            4 :     double rt = RandHelper::randNorm(mean, var, &myResponseTimeRNG);
    1189              : #ifdef DEBUG_DYNAMIC_TOC
    1190              :     std::cout << "  mean=" << mean << ", variance=" << var << " => sampled responseTime=" << rt << std::endl;
    1191              : #endif
    1192              :     int it_count = 0;
    1193            4 :     while (rt < 0 && it_count < MAX_RESPONSETIME_SAMPLE_TRIES) {
    1194            0 :         rt = RandHelper::randNorm(mean, var, &myResponseTimeRNG);
    1195            0 :         it_count++;
    1196              :     }
    1197            4 :     if (rt < 0) {
    1198              :         // Didn't generate a positive random response time => use mean
    1199              :         rt = mean;
    1200              :     }
    1201            4 :     return rt;
    1202              : }
    1203              : 
    1204              : double
    1205            4 : MSDevice_ToC::interpolateVariance(double leadTime, double pMRM) {
    1206              : #ifdef DEBUG_DYNAMIC_TOC
    1207              :     std::cout << "interpolateVariance() leadTime=" << leadTime << ", pMRM=" << pMRM << std::endl;
    1208              : #endif
    1209              :     // Calculate indices for surrounding values in lookup tables
    1210              : 
    1211              :     // Find largest p_{i-1} < pMRM < p_{i}
    1212            4 :     const auto pi = std::lower_bound(lookupResponseTimeMRMProbs.begin(), lookupResponseTimeMRMProbs.end(), pMRM);
    1213            4 :     if (pi == lookupResponseTimeMRMProbs.end()) {
    1214              :         // requested probability lies outside lookup table.
    1215              :         // => return maximal variance value
    1216              :         return MAX_RESPONSETIME_VARIANCE;
    1217              :     }
    1218            4 :     const size_t pi1 = pi - lookupResponseTimeMRMProbs.begin();
    1219              :     assert(pi1 > 0);
    1220            4 :     const size_t pi0 = pi1 - 1;
    1221            4 :     const double cp = (pMRM - * (pi - 1)) / (*pi - * (pi - 1));
    1222              : 
    1223              : #ifdef DEBUG_DYNAMIC_TOC
    1224              :     std::cout << " p[=" << pi0 << "]=" << *(pi - 1) << ", p[=" << pi1 << "]=" << *pi << " => cp=" << cp << std::endl;
    1225              : #endif
    1226              : 
    1227              :     // Find largest p_{i-1} < pMRM < p_{i}
    1228            4 :     auto li = std::lower_bound(lookupResponseTimeLeadTimes.begin(), lookupResponseTimeLeadTimes.end(), leadTime);
    1229            4 :     if (li == lookupResponseTimeLeadTimes.begin()) {
    1230              :         // Given lead time smaller than minimal lookup-value.
    1231              :         // Use minimal value from lookup table instead
    1232            0 :         leadTime = *li;
    1233              :         li = lookupResponseTimeLeadTimes.begin() + 1;
    1234            4 :     } else if (li == lookupResponseTimeLeadTimes.end()) {
    1235              :         // Given leadTime exceeds values in lookup table
    1236              :         // => induce extrapolation
    1237              :         li--;
    1238              :     }
    1239              :     const size_t li1 = li - lookupResponseTimeLeadTimes.begin();
    1240              :     const size_t li0 = li1 - 1;
    1241            4 :     const double cl = (leadTime - * (li - 1)) / (*li - * (li - 1));
    1242              : 
    1243              : #ifdef DEBUG_DYNAMIC_TOC
    1244              :     std::cout << " l[=" << li0 << "]=" << *(li - 1) << ", l[=" << li1 << "]=" << *li << " => cp=" << cl << std::endl;
    1245              : #endif
    1246              : 
    1247              :     // 2D interpolation for variance
    1248              :     // First, interpolate (or extrapolate) variances along leadTimes
    1249            4 :     const double var00 = lookupResponseTimeVariances[pi0][li0];
    1250            4 :     const double var01 = lookupResponseTimeVariances[pi0][li1];
    1251            4 :     const double var10 = lookupResponseTimeVariances[pi1][li0];
    1252            4 :     const double var11 = lookupResponseTimeVariances[pi1][li1];
    1253            4 :     const double var_0 = var00 + (var01 - var00) * cl;
    1254            4 :     const double var_1 = var10 + (var11 - var10) * cl;
    1255              :     // From these, interpolate along the pMRM-axis
    1256            4 :     const double var = var_0 + (var_1 - var_0) * cp;
    1257              : #ifdef DEBUG_DYNAMIC_TOC
    1258              :     std::cout << " var00=" << var00 << ", var01=" << var01 << " var10=" << var10 << ", var11=" << var11
    1259              :               << " var_0=" << var_0 << ", var_1=" << var_1 << ", var=" << var << std::endl;
    1260              : #endif
    1261            4 :     return var;
    1262              : }
    1263              : 
    1264              : // Grid of the response time distribution.
    1265              : // Generated by the script generateResponseTimeDistributions.py, see Appendix to TransAID Deliverable 3.1v2.
    1266              : // Probability for an MRM to occur (start with 0.0, end with 0.5)
    1267              : std::vector<double> MSDevice_ToC::lookupResponseTimeMRMProbs = {0.0, 0.05, 0.1, 0.15000000000000002, 0.2, 0.25, 0.30000000000000004, 0.35000000000000003, 0.4, 0.45, 0.5};
    1268              : // Lead time grid
    1269              : std::vector<double> MSDevice_ToC::lookupResponseTimeLeadTimes = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.7999999999999999, 0.8999999999999999, 0.9999999999999999, 1.0999999999999999, 1.2, 1.3, 1.4, 1.5, 1.5999999999999999, 1.7, 1.8, 1.9, 2.0, 2.25, 2.5, 2.75, 3.0, 3.25, 3.5, 3.75, 4.0, 4.25, 4.5, 4.75, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10.0, 10.5, 11.0, 11.5, 12.0, 12.5, 13.0, 13.5, 14.0, 14.5, 15.0, 15.5, 16.0, 16.5, 17.0, 17.5, 18.0, 18.5, 19.0, 19.5, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0, 32.0, 33.0, 34.0, 35.0, 36.0, 37.0, 38.0, 39.0, 40.0, 41.0, 42.0, 43.0, 44.0, 45.0, 46.0, 47.0, 48.0, 49.0, 50.0};
    1270              : 
    1271              : // Variances of the response time distribution.
    1272              : std::vector<std::vector<double> > MSDevice_ToC::lookupResponseTimeVariances = {
    1273              :     {0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001},
    1274              :     {0.018238371642696278, 0.03647674328603705, 0.054715114926535656, 0.07295348656987645, 0.09119185821321724, 0.10943022985371582, 0.12766860149705656, 0.14590697314039733, 0.16414534478089599, 0.18238371642423673, 0.2006220880675775, 0.21886045971091828, 0.2370988313514169, 0.25533720299475765, 0.27357557463809845, 0.291813946278597, 0.3100523179219377, 0.32829068956527846, 0.3465290612057772, 0.36476743284911795, 0.4103633619560487, 0.45595929106297967, 0.5015552201670682, 0.5471511492739992, 0.59274707838093, 0.6383430074850186, 0.6839389365919495, 0.7295348656988803, 0.7751307948058112, 0.8207267239098999, 0.8663226530168309, 0.9119185821237615, 1.003110440334781, 1.0943022985486428, 1.1854941567596624, 1.2766860149735242, 1.3678778731845436, 1.4590697313984053, 1.622588042723657, 1.8236013818166044, 2.0271872430355344, 2.2329896377033402, 2.440681612959606, 2.6499766330096066, 2.8606328744048484, 3.0724517481497657, 3.285273075453899, 3.4989689745182173, 3.713437758931686, 3.928598499444084, 4.144386478335934, 4.360749535794346, 4.577645204319768, 4.795038495182951, 5.012900204026633, 5.231205620052272, 5.449933544477286, 5.669065543877604, 5.888585381094657, 6.108478580034079, 6.328732091514834, 6.5493340353396325, 6.991540386888257, 7.4350193801571836, 7.8797023900653835, 8.325528107903486, 8.772441019472117, 9.220390365425358, 9.66932940241786, 10.11921485679467, 10.570006505095746, 11.021666840703753, 11.474160800924851, 11.927455537955435, 12.381520222795276, 12.836325874663427, 13.291845210806684, 13.748052512926236, 14.204923507573522, 14.662435258383752, 15.120566068535554, 15.57929539219183, 16.03860375377652, 16.498472674274336, 16.958884603774735, 17.41982285960362, 17.881271569514066, 18.343215619413176, 18.805640605235663, 19.268532788517863, 19.731879055399546, 20.195666878723525},
    1275              :     {0.023394708584543455, 0.04678941716973141, 0.07018412575207719, 0.09357883433726513, 0.11697354292245306, 0.14036825150764104, 0.16376296009282898, 0.18715766867517475, 0.2105523772603627, 0.23394708584555063, 0.25734179443073857, 0.2807365030130844, 0.3041312115982723, 0.3275259201834602, 0.3509206287686481, 0.37431533735099387, 0.3977100459361818, 0.42110475452136986, 0.4444994631065578, 0.46789417168890357, 0.5263809431504523, 0.5848677146120012, 0.6433544860735498, 0.7018412575350985, 0.7603280289966473, 0.8188148004581961, 0.8773015719197449, 0.9357883433784517, 0.9942751148400004, 1.0527618863015489, 1.111248657763098, 1.169735429224647, 1.2867089721477445, 1.4036825150708419, 1.520656057991097, 1.6376296009141948, 1.7546031438372918, 1.8715766867603902, 2.080324923070349, 2.3356056603653466, 2.592695753086048, 2.851065033244823, 3.110348235805368, 3.37030701064756, 3.630792243424829, 3.8917140872434826, 4.153020535352749, 4.414682984212653, 4.676686852454919, 4.939025633083471, 5.201697195938797, 5.4647015339779985, 5.728039423002128, 5.991711652753062, 6.255718611539178, 6.520060086487768, 6.784735192689795, 7.0497423770254475, 7.315079462951026, 7.580743715621537, 7.846731914823575, 8.113040428416943, 8.646602223970579, 9.181394311584102, 9.717379133745458, 10.25451769188949, 10.792770521511661, 11.332098388641393, 11.872462773672844, 12.41382619675905, 12.956152426938662, 13.499406606935544, 14.04355531739462, 14.588566598200957, 15.134409939740127, 15.681056253544272, 16.228477829207687, 16.776648282531472, 17.32554249848686, 17.875136571609353, 18.425407745596857, 18.976334353419617, 19.527895758814104, 20.080072299738145, 20.632845234156534, 21.18619668838177, 21.740109608063758, 22.294567711842525, 22.849555447666962, 23.405057951674344, 23.96106100953682, 24.517551020220964},
    1276              :     {0.028809965676139145, 0.05761993135292278, 0.08642989702686427, 0.11523986270364789, 0.14404982838043154, 0.172859794054373, 0.20166975973115658, 0.23047972540794023, 0.2592896910818817, 0.2880996567586654, 0.31690962243544896, 0.34571958811223263, 0.37452955378617403, 0.4033395194629576, 0.4321494851397413, 0.4609594508136828, 0.4897694164904665, 0.51857938216725, 0.5473893478411916, 0.5761993135179752, 0.6482242277085132, 0.7202491418990512, 0.7922740560867471, 0.864298970277285, 0.9363238844678232, 1.0083487986555189, 1.0803737128460569, 1.152398627036595, 1.224423541227133, 1.296448455414829, 1.368473369605367, 1.4404982837959048, 1.584548112174139, 1.7285979405552145, 1.8726477689334486, 2.0166975973145242, 2.1607474256927586, 2.3047972540738346, 2.5572219533483644, 2.8623099438447785, 3.167154753839855, 3.4715923078311928, 3.775618300633292, 4.079301412505033, 4.3827364323759, 4.686020985499979, 4.989245061612653, 5.2924871133699085, 5.595813357348367, 5.89927852360174, 6.202927167199209, 6.506795109670751, 6.810910812533207, 7.115296603265157, 7.419969732096102, 7.724943265058281, 8.030226829842663, 8.33582723446787, 8.641748978492437, 8.947994674556652, 9.254565395777925, 9.561460961999748, 10.17622101728854, 10.792256328037844, 11.409539737303032, 12.02803871883203, 12.647717622463388, 13.268539213916304, 13.890465727714453, 14.513459582113466, 15.137483858085837, 15.76250261298258, 16.388481078046894, 17.015385774331957, 17.643184571383188, 18.271846706039163, 18.901342773672106, 19.531644700723955, 20.16272570482796, 20.79456024708863, 21.427123979740387, 22.06039369148417, 22.694347252144688, 23.32896355779389, 23.964222477085105, 24.600104799357926, 25.23659218482918, 25.873667117046345, 26.51131285772261, 27.149513403967962, 27.788253447896256, 28.427518338543063},
    1277              :     {0.03496845765860337, 0.06993691531785123, 0.1049053729770991, 0.13987383063634692, 0.17484228829559478, 0.20981074595200053, 0.24477920361124836, 0.2797476612704962, 0.314716118929744, 0.34968457658899194, 0.38465303424823977, 0.41962149190748765, 0.4545899495638933, 0.48955840722314126, 0.5245268648823892, 0.5594953225416369, 0.5944637802008848, 0.6294322378601326, 0.6644006955193805, 0.6993691531757862, 0.7867902973239058, 0.8742114414720256, 0.961632585617303, 1.0490537297654225, 1.1364748739135424, 1.2238960180588196, 1.3113171622069395, 1.3987383063550594, 1.4861594505003368, 1.5735805946484562, 1.6610017387965759, 1.748422882941853, 1.9232651712352506, 2.0981074595314895, 2.272949747824887, 2.4477920361182846, 2.6226343244145234, 2.7974766127079205, 3.0926745755509586, 3.44395841916428, 3.7929654946149927, 4.140199155580832, 4.48610487276643, 4.8310499148399675, 5.175327720605737, 5.519169410160118, 5.862755881539858, 6.20622837304298, 6.549697059107542, 6.893247832651301, 7.236947584569466, 7.580848293751031, 7.924990195098607, 8.2694042393908, 8.614114010475241, 8.959137226336916, 9.30448692001335, 9.650172373181427, 9.996199857775714, 10.342573227835842, 10.689294393844476, 11.036363704475946, 11.73154213703699, 12.428090426873897, 13.125980076789245, 13.825176212794954, 14.52564028426291, 15.227331883606062, 15.930209972250445, 16.634233702118422, 17.339362959284276, 18.045558715641334, 18.752783247333983, 19.461000260660008, 20.170174953762714, 20.880274034013603, 21.591265705145904, 22.303119634055196, 23.015806904341318, 23.7292999616137, 24.443572554090043, 25.158599671023588, 25.874357480669964, 26.590823269047004, 27.30797538027189, 28.025793159035764, 28.74425689552527, 29.46334777297606, 30.183047817969005, 30.903339853423454, 31.624207454305022, 32.345634905899644},
    1278              :     {0.04208452197242317, 0.08416904394549082, 0.12625356591855852, 0.16833808789162616, 0.21042260986469383, 0.25250713183776147, 0.294591653807987, 0.33667617578105463, 0.3787606977541223, 0.42084521972719, 0.46292974170025764, 0.5050142636733252, 0.5470987856463931, 0.5891833076194606, 0.6312678295925284, 0.6733523515627537, 0.7154368735358214, 0.7575213955088891, 0.7996059174819568, 0.8416904394550245, 0.9469017443876938, 1.0521130493203628, 1.1573243542501899, 1.2625356591828591, 1.3677469641155282, 1.472958269045355, 1.5781695739780248, 1.6833808789106937, 1.7885921838433625, 1.8938034887731896, 1.9990147937058587, 2.104226098638527, 2.314648708501024, 2.5250713183663627, 2.7354939282288586, 2.9459165380941967, 3.1563391479566936, 3.3667617578220317, 3.703839316684887, 4.098607599735211, 4.490071039515135, 4.879192386567447, 5.266673871161598, 5.6530296960510835, 6.038639278868162, 6.423784955842712, 6.808678484059117, 7.1934797498117895, 7.578310096881422, 7.9632619279700085, 8.348405702022065, 8.733795092290785, 9.119470830182808, 9.505463599150936, 9.891796234154242, 10.278485408041451, 10.665542934966393, 11.05297678524097, 11.440791880843797, 11.828990722803214, 12.217573888696098, 12.606540429161571, 13.385614043672865, 14.166184035906006, 14.948213302277296, 15.731659164963906, 16.51647601334669, 17.302617053034968, 18.09003546045466, 18.87868513730469, 19.66852119352658, 20.459500245021562, 21.251580584675224, 22.044722266798285, 22.838887132598156, 23.634038796019215, 24.430142603281702, 25.22716557558935, 26.025076341551085, 26.823845063912813, 27.62344336382784, 28.423844244828874, 29.22502201803638, 30.026952229552563, 30.82961159071451, 31.63297791152784, 32.43703003753926, 33.24174779014256, 34.047111910360435, 34.85310400598881, 35.65970650197814, 36.46690259392711},
    1279              :     {0.05029020480396514, 0.10058040960573261, 0.15087061441034225, 0.2011608192121097, 0.2514510240167194, 0.301741228821329, 0.35203143362309647, 0.40232163842770624, 0.45261184322947356, 0.5029020480340831, 0.5531922528358507, 0.6034824576404602, 0.6537726624450699, 0.7040628672468374, 0.7543530720514469, 0.8046432768532146, 0.8549334816578241, 0.9052236864595916, 0.9555138912642014, 1.0058040960688106, 1.1315296080760717, 1.2572551200833324, 1.382980632093436, 1.5087061441006968, 1.6344316561107992, 1.7601571681180603, 1.8858826801253215, 2.0116081921354243, 2.137333704142684, 2.263059216152788, 2.3887847281600485, 2.514510240170152, 2.765961264184674, 3.017412288202038, 3.2688633122194015, 3.520314336236765, 3.7717653602541295, 4.023216384271493, 4.402923686706604, 4.840923169412718, 5.275628140231794, 5.708106387011112, 6.139096012777341, 6.569117835239806, 6.998545742885471, 7.427651941064436, 7.856636809801444, 8.28564907733453, 8.714799743029685, 9.144171870687785, 9.573827594895418, 10.00381321001211, 10.43416291693517, 10.864901615202994, 11.296047006509264, 11.72761119486633, 12.159601914603718, 12.592023480161025, 13.024877525833228, 13.458163585558754, 13.891879549849177, 14.326022027631314, 15.195568219985953, 16.066758980781113, 16.93954397110994, 17.813869202173244, 18.68967930447209, 19.566918991345418, 20.44553399181503, 21.325471630737475, 22.206681173178218, 23.089114010781095, 23.972723742457497, 24.857466184805716, 25.743299336515662, 26.63018331333154, 27.518080264958197, 28.4069542817556, 29.296771296561822, 30.187498985305254, 31.07910666877645, 31.97156521721369, 32.86484695863455, 33.75892559154721, 34.653776102328635, 35.54937468734068, 36.44569867980954, 37.34272648128694, 38.24043749755077, 39.13881207875172, 40.03783146350794, 40.937477726773984},
    1280              :     {0.05974016468300759, 0.11948032936381749, 0.17922049404462742, 0.23896065872827943, 0.29870082340908927, 0.35844098808989927, 0.4181811527735513, 0.47792131745436117, 0.5376614821380133, 0.5974016468188231, 0.657141811499633, 0.7168819761832851, 0.7766221408640949, 0.8363623055449051, 0.8961024702285572, 0.955842634909367, 1.0155827995930191, 1.0753229642738293, 1.135063128954639, 1.1948032936382913, 1.344153705341737, 1.493504117048025, 1.6428545287514704, 1.7922049404549163, 1.9415553521612046, 2.0909057638646504, 2.2402561755709387, 2.389606587274385, 2.5389569989806726, 2.688307410684118, 2.8376578223904056, 2.987008234093852, 3.2857090575035857, 3.58440988091332, 3.8831107043230535, 4.181811527729945, 4.48051235113968, 4.779213174549414, 5.204876111923692, 5.688848562937568, 6.170159044583231, 6.6497495644421285, 7.128261753669921, 7.606142949678828, 8.083710709627423, 8.561193555361694, 9.038757543068261, 9.516524068724227, 9.99458208377549, 10.47299664830626, 10.951815027051936, 11.431071102373838, 11.910788612986488, 12.39098355983018, 12.871666012589971, 13.352841479046571, 13.834511951858257, 14.316676714667919, 14.799332966945224, 15.282476311040416, 15.766101133711286, 16.250200906162327, 17.219795978620663, 18.1911988298489, 19.164342959599296, 20.139160814458737, 21.115585503946967, 22.093551853025446, 23.07299702417972, 24.053860858945782, 25.036086036434696, 26.019618113131642, 27.004405486541614, 27.990399311257423, 28.977553386435417, 29.965824027565322, 30.95516993094154, 31.94555203660525, 32.93693339332716, 33.92927902800424, 34.92255582087156, 35.91673238727074, 36.91177896637648, 37.907667316880286, 38.90437061956949, 39.90186338652862, 40.90012137664726, 41.899121517093974, 42.89884183037187, 43.8992613666098, 44.90036014068208, 45.90211907383619},
    1281              :     {0.07067515415184052, 0.14135030830148337, 0.2120254624511261, 0.2827006166036112, 0.35337577075325394, 0.4240509249028968, 0.49472607905538185, 0.5654012332050246, 0.6360763873575095, 0.7067515415071527, 0.7774266956567951, 0.8481018498092803, 0.9187770039589231, 0.9894521581085659, 1.060127312261051, 1.1308024664106937, 1.2014776205603366, 1.2721527747128218, 1.3428279288624643, 1.41350308301495, 1.5901909683904774, 1.7668788537660056, 1.943566739144376, 2.120254624519904, 2.2969425098982743, 2.473630395273803, 2.6503182806493313, 2.8270061660277013, 3.0036940514032295, 3.1803819367816004, 3.3570698221571273, 3.5337577075354982, 3.8871334782865548, 4.240509249040453, 4.593885019794351, 4.947260790548251, 5.300636561302148, 5.654012332053204, 6.131630444292413, 6.6672022906208355, 7.200987739963464, 7.733716006955079, 8.265882445019285, 8.797830454475601, 9.32980159851235, 9.861967438834494, 10.394450401173598, 10.927337816806162, 11.460691587201293, 11.994554966496775, 12.528957402009762, 13.06391803975272, 13.599448295828148, 14.135553763816139, 14.672235643520898, 15.209491820318211, 15.747317686564726, 16.285706770680626, 16.82465122144653, 17.364142182462015, 17.904170082649248, 18.444724862108774, 19.52737339128757, 20.612003289072593, 21.69853012990063, 22.786871401229217, 23.87694757433194, 24.968682680039276, 26.062004572321317, 27.156844995848896, 28.253139532174295, 29.350827472729005, 30.449851649907924, 31.55015824661291, 32.651696597281045, 33.75441898881355, 34.85828046658357, 35.96323864863796, 37.06925354984671, 38.176287416815526, 39.2843045737864, 40.39327127936956, 41.50315559373177, 42.613927255723794, 43.72555756930443, 44.838019298684486, 45.951286571522466, 47.065334789581065, 48.18014054623036, 49.29568155028052, 50.41193655559852, 51.52888529603219},
    1282              :     {0.0834623671324666, 0.16692473426273555, 0.2503871013958466, 0.33384946852611547, 0.4173118356592266, 0.5007742027894957, 0.5842365699226064, 0.6676989370528754, 0.7511613041859866, 0.8346236713162553, 0.9180860384493664, 1.0015484055796355, 1.0850107727127467, 1.1684731398430155, 1.2519355069761264, 1.3353978741063957, 1.4188602412395066, 1.5023226083697758, 1.5857849755028866, 1.6692473426331556, 1.8779032604630912, 2.0865591782930264, 2.29521509612012, 2.5038710139500555, 2.7125269317799905, 2.921182849609927, 3.1298387674370196, 3.338494685266956, 3.547150603096892, 3.7558065209268268, 3.96446243875392, 4.173118356583855, 4.590430192243725, 5.007742027900754, 5.425053863557784, 5.842365699217655, 6.259677534874682, 6.676989370534554, 7.215284811865045, 7.810942636066625, 8.405713438558344, 9.000109193262631, 9.594476065866042, 10.189051324756685, 10.783998757795331, 11.379431470741277, 11.975426983124095, 12.572037465005534, 13.169296821117609, 13.767225679430393, 14.365834957075359, 14.965128442509108, 15.565104686191797, 16.165758398192054, 16.767081489665355, 17.369063854126264, 17.971693956723634, 18.574959280506526, 19.178846665295886, 19.78334256540095, 20.38843324553279, 20.994104929469565, 22.20713664504607, 23.42233029997001, 24.63958259994195, 25.858795291719396, 27.079875555554814, 28.302736078822026, 29.527294941445533, 30.75347539415742, 31.981205580215, 33.21041823195959, 34.44105036161415, 35.67304295805245, 36.90634069627536, 38.14089166337484, 39.3766471025938, 40.61356117597085, 41.851590745280404, 43.090695170440334, 44.33083612445286, 45.57197742365028, 46.814084872185866, 48.05712611949615, 49.301070529748834, 50.54588906213925, 51.79155416112571, 53.0380396556748, 54.285320666751495, 55.533373522224736, 56.782175678619716, 58.031705649011975},
    1283              :     {0.09864342769295685, 0.19728685538371601, 0.2959302830773173, 0.39457371076807657, 0.49321713846167803, 0.5918605661524371, 0.6905039938460386, 0.7891474215367978, 0.887790849230399, 0.9864342769211584, 1.0850777046147597, 1.1837211323055188, 1.2823645599991202, 1.38100798768988, 1.4796514153834808, 1.5782948430742403, 1.6769382707678415, 1.7755816984586006, 1.874225126152202, 1.972868553842961, 2.219477123074122, 2.4660856923052834, 2.7126942615364444, 2.9593028307647646, 3.2059113999959257, 3.4525199692270867, 3.6991285384582473, 3.945737107686567, 4.192345676917727, 4.438954246148888, 4.68556281538005, 4.932171384608369, 5.425388523070691, 5.918605661530172, 6.411822799992494, 6.905039938451975, 7.398257076914296, 7.891474215373778, 8.502335361374866, 9.169831074405188, 9.837265003168877, 10.504960425335845, 11.173131332846934, 11.841919360545138, 12.511417180930938, 13.181683762841976, 13.85275456878272, 14.524648510968875, 15.197372779403622, 15.870926242469201, 16.545301871890324, 17.220488489846183, 17.896472038316816, 18.573236507380663, 19.250764617377587, 19.929038321651447, 20.608039177427425, 21.287748619021162, 21.968148158299684, 22.64921953063529, 23.330944799863957, 24.013306432352234, 25.37987095153259, 26.74878238692951, 28.119918223260417, 29.4931641334551, 30.8684136985658, 32.245567980998565, 33.624535031317535, 35.005229375702534, 36.38757151118004, 37.77148742362557, 39.156908136182956, 40.54376929127801, 41.93201076678101, 43.32157632534552, 44.712413295099445, 46.1044722794653, 47.497706893719666, 48.892073525949804, 50.2875311201024, 51.68404097903562, 53.081566585544806, 54.48007343965984, 55.87952891050276, 57.27990210130182, 58.68116372625177, 60.08328599798667, 61.48624252468206, 62.890008215820075, 64.29455919573915, 65.6998727243063},
    1284              : };
    1285              : 
    1286              : 
    1287              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1