LCOV - code coverage report
Current view: top level - src/microsim/devices - MSDevice_ToC.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 499 596 83.7 %
Date: 2024-04-30 15:40:33 Functions: 36 39 92.3 %

          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             : #define DEFAULT_MANUAL_TYPE ""
      86             : #define DEFAULT_AUTOMATED_TYPE ""
      87             : 
      88             : // Maximal tries to sample a positive value from the gaussian distribution
      89             : // used for the driver response time when a TOR is issued. (the distribution is assumed truncated at zero)
      90             : #define MAX_RESPONSETIME_SAMPLE_TRIES 100
      91             : // Maximal variance of responsetimes (returned for pMRM outside lookup table, i.e. pMRM>0.5), see interpolateVariance()
      92             : #define MAX_RESPONSETIME_VARIANCE 10000
      93             : 
      94             : 
      95             : // ---------------------------------------------------------------------------
      96             : // static members
      97             : // ---------------------------------------------------------------------------
      98             : std::set<MSDevice_ToC*, ComparatorNumericalIdLess> MSDevice_ToC::myInstances = std::set<MSDevice_ToC*, ComparatorNumericalIdLess>();
      99             : std::set<std::string> MSDevice_ToC::createdOutputFiles;
     100             : int MSDevice_ToC::LCModeMRM = 768; // = 0b001100000000 - no autonomous changes, no speed adaptation
     101             : SumoRNG MSDevice_ToC::myResponseTimeRNG("toc");
     102             : 
     103             : 
     104             : // ===========================================================================
     105             : // method definitions
     106             : // ===========================================================================
     107             : // ---------------------------------------------------------------------------
     108             : // static initialisation methods
     109             : // ---------------------------------------------------------------------------
     110             : void
     111       36322 : MSDevice_ToC::insertOptions(OptionsCont& oc) {
     112       36322 :     oc.addOptionSubTopic("ToC Device");
     113       72644 :     insertDefaultAssignmentOptions("toc", "ToC Device", oc);
     114             : 
     115       72644 :     oc.doRegister("device.toc.manualType", new Option_String());
     116       72644 :     oc.addDescription("device.toc.manualType", "ToC Device", TL("Vehicle type for manual driving regime."));
     117       72644 :     oc.doRegister("device.toc.automatedType", new Option_String());
     118       72644 :     oc.addDescription("device.toc.automatedType", "ToC Device", TL("Vehicle type for automated driving regime."));
     119       36322 :     oc.doRegister("device.toc.responseTime", new Option_Float(DEFAULT_RESPONSE_TIME));
     120       72644 :     oc.addDescription("device.toc.responseTime", "ToC Device", TL("Average response time needed by a driver to take back control."));
     121       36322 :     oc.doRegister("device.toc.recoveryRate", new Option_Float(DEFAULT_RECOVERY_RATE));
     122       72644 :     oc.addDescription("device.toc.recoveryRate", "ToC Device", TL("Recovery rate for the driver's awareness after a ToC."));
     123       36322 :     oc.doRegister("device.toc.lcAbstinence", new Option_Float(DEFAULT_LCABSTINENCE));
     124       72644 :     oc.addDescription("device.toc.lcAbstinence", "ToC Device", TL("Attention level below which a driver restrains from performing lane changes (value in [0,1])."));
     125       36322 :     oc.doRegister("device.toc.initialAwareness", new Option_Float(DEFAULT_INITIAL_AWARENESS));
     126       72644 :     oc.addDescription("device.toc.initialAwareness", "ToC Device", TL("Average awareness a driver has initially after a ToC (value in [0,1])."));
     127       36322 :     oc.doRegister("device.toc.mrmDecel", new Option_Float(DEFAULT_MRM_DECEL));
     128       72644 :     oc.addDescription("device.toc.mrmDecel", "ToC Device", TL("Deceleration rate applied during a 'minimum risk maneuver'."));
     129       36322 :     oc.doRegister("device.toc.dynamicToCThreshold", new Option_Float(DEFAULT_DYNAMIC_TOC_THRESHOLD));
     130       72644 :     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."));
     131       36322 :     oc.doRegister("device.toc.dynamicMRMProbability", new Option_Float(DEFAULT_MRM_PROBABILITY));
     132       72644 :     oc.addDescription("device.toc.dynamicMRMProbability", "ToC Device", TL("Probability that a dynamically triggered TOR is not answered in time."));
     133       36322 :     oc.doRegister("device.toc.mrmKeepRight", new Option_Bool(false));
     134       72644 :     oc.addDescription("device.toc.mrmKeepRight", "ToC Device", TL("If true, the vehicle tries to change to the right during an MRM."));
     135       72644 :     oc.doRegister("device.toc.mrmSafeSpot", new Option_String());
     136       72644 :     oc.addDescription("device.toc.mrmSafeSpot", "ToC Device", TL("If set, the vehicle tries to reach the given named stopping place during an MRM."));
     137       36322 :     oc.doRegister("device.toc.mrmSafeSpotDuration", new Option_Float(60.));
     138       72644 :     oc.addDescription("device.toc.mrmSafeSpotDuration", "ToC Device", TL("Duration the vehicle stays at the safe spot after an MRM."));
     139       36322 :     oc.doRegister("device.toc.maxPreparationAccel", new Option_Float(0.0));
     140       72644 :     oc.addDescription("device.toc.maxPreparationAccel", "ToC Device", TL("Maximal acceleration that may be applied during the ToC preparation phase."));
     141       36322 :     oc.doRegister("device.toc.ogNewTimeHeadway", new Option_Float(-1.0));
     142       72644 :     oc.addDescription("device.toc.ogNewTimeHeadway", "ToC Device", TL("Timegap for ToC preparation phase."));
     143       36322 :     oc.doRegister("device.toc.ogNewSpaceHeadway", new Option_Float(-1.0));
     144       72644 :     oc.addDescription("device.toc.ogNewSpaceHeadway", "ToC Device", TL("Additional spacing for ToC preparation phase."));
     145       36322 :     oc.doRegister("device.toc.ogMaxDecel", new Option_Float(-1.0));
     146       72644 :     oc.addDescription("device.toc.ogMaxDecel", "ToC Device", TL("Maximal deceleration applied for establishing increased gap in ToC preparation phase."));
     147       36322 :     oc.doRegister("device.toc.ogChangeRate", new Option_Float(-1.0));
     148       72644 :     oc.addDescription("device.toc.ogChangeRate", "ToC Device", TL("Rate of adaptation towards the increased headway during ToC preparation."));
     149       36322 :     oc.doRegister("device.toc.useColorScheme", new Option_Bool(true));
     150       72644 :     oc.addDescription("device.toc.useColorScheme", "ToC Device", TL("Whether a coloring scheme shall by applied to indicate the different ToC stages."));
     151       72644 :     oc.doRegister("device.toc.file", new Option_String());
     152       72644 :     oc.addDescription("device.toc.file", "ToC Device", TL("Switches on output by specifying an output filename."));
     153       36322 : }
     154             : 
     155             : 
     156             : void
     157     4655777 : MSDevice_ToC::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into) {
     158     4655777 :     OptionsCont& oc = OptionsCont::getOptions();
     159     9311554 :     if (equippedByDefaultAssignmentOptions(oc, "toc", v, false)) {
     160          90 :         if (MSGlobals::gUseMesoSim) {
     161           0 :             WRITE_WARNING(TL("ToC device is not supported by the mesoscopic simulation."));
     162           0 :             return;
     163             :         }
     164         180 :         const std::string manualType = getStringParam(v, oc, "toc.manualType", DEFAULT_MANUAL_TYPE, true);
     165         182 :         const std::string automatedType = getStringParam(v, oc, "toc.automatedType", DEFAULT_AUTOMATED_TYPE, true);
     166         180 :         const SUMOTime responseTime = TIME2STEPS(getFloatParam(v, oc, "toc.responseTime", DEFAULT_RESPONSE_TIME, false));
     167          86 :         const double recoveryRate = getFloatParam(v, oc, "toc.recoveryRate", DEFAULT_RECOVERY_RATE, false);
     168          86 :         const double lcAbstinence = getFloatParam(v, oc, "toc.lcAbstinence", DEFAULT_LCABSTINENCE, false);
     169          86 :         const double initialAwareness = getFloatParam(v, oc, "toc.initialAwareness", DEFAULT_INITIAL_AWARENESS, false);
     170          86 :         const double mrmDecel = getFloatParam(v, oc, "toc.mrmDecel", DEFAULT_MRM_DECEL, false);
     171         176 :         const bool useColoring = getBoolParam(v, oc, "toc.useColorScheme", true, false);
     172          86 :         const std::string deviceID = "toc_" + v.getID();
     173          86 :         const std::string file = getOutputFilename(v, oc);
     174          86 :         const OpenGapParams ogp = getOpenGapParams(v, oc);
     175          86 :         const double dynamicToCThreshold = getFloatParam(v, oc, "toc.dynamicToCThreshold", DEFAULT_DYNAMIC_TOC_THRESHOLD, false);
     176          86 :         const double dynamicMRMProbability = getDynamicMRMProbability(v, oc);
     177          86 :         const bool mrmKeepRight = getBoolParam(v, oc, "toc.mrmKeepRight", false, false);
     178         176 :         const std::string mrmSafeSpot = getStringParam(v, oc, "toc.mrmSafeSpot", "", false);
     179         172 :         const SUMOTime mrmSafeSpotDuration = TIME2STEPS(getFloatParam(v, oc, "toc.mrmSafeSpotDuration", 60., false));
     180          86 :         const double maxPreparationAccel = getFloatParam(v, oc, "toc.maxPreparationAccel", 0.0, false);
     181             :         // build the device
     182             :         MSDevice_ToC* device = new MSDevice_ToC(v, deviceID, file,
     183             :                                                 manualType, automatedType, responseTime, recoveryRate,
     184             :                                                 lcAbstinence, initialAwareness, mrmDecel, dynamicToCThreshold,
     185             :                                                 dynamicMRMProbability, maxPreparationAccel, mrmKeepRight,
     186          86 :                                                 mrmSafeSpot, mrmSafeSpotDuration, useColoring, ogp);
     187          86 :         into.push_back(device);
     188             :     }
     189             : }
     190             : 
     191             : 
     192             : std::string
     193          86 : MSDevice_ToC::getOutputFilename(const SUMOVehicle& v, const OptionsCont& oc) {
     194             :     // Default of "" means no output
     195          86 :     std::string file = "";
     196         172 :     if (v.getParameter().hasParameter("device.toc.file")) {
     197             :         try {
     198         198 :             file = v.getParameter().getParameter("device.toc.file", file);
     199           0 :         } catch (...) {
     200           0 :             WRITE_WARNINGF(TL("Invalid value '%' for vehicle parameter 'ssm.measures'"), v.getParameter().getParameter("device.toc.file", file));
     201           0 :         }
     202          40 :     } else if (v.getVehicleType().getParameter().hasParameter("device.toc.file")) {
     203             :         try {
     204           0 :             file = v.getVehicleType().getParameter().getParameter("device.toc.file", file);
     205           0 :         } catch (...) {
     206           0 :             WRITE_WARNINGF(TL("Invalid value '%' for vType parameter 'ssm.measures'"), v.getVehicleType().getParameter().getParameter("device.toc.file", file));
     207           0 :         }
     208             :     } else {
     209          80 :         file = oc.getString("device.toc.file") == "" ? file : oc.getString("device.toc.file");
     210             :     }
     211          86 :     return file;
     212             : }
     213             : 
     214             : 
     215             : double
     216          86 : MSDevice_ToC::getDynamicMRMProbability(const SUMOVehicle& v, const OptionsCont& oc) {
     217          86 :     double pMRM = getFloatParam(v, oc, "toc.dynamicMRMProbability", DEFAULT_MRM_PROBABILITY, false);
     218          86 :     if (pMRM < 0 || pMRM > 0.5) {
     219           2 :         const double pMRMTrunc = MAX2(0.0, MIN2(0.5, pMRM));
     220           4 :         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));
     221           2 :         return pMRMTrunc;
     222             :     }
     223             :     return pMRM;
     224             : }
     225             : 
     226             : 
     227             : MSDevice_ToC::OpenGapParams
     228          86 : MSDevice_ToC::getOpenGapParams(const SUMOVehicle& v, const OptionsCont& oc) {
     229          86 :     double timegap = getFloatParam(v, oc, "toc.ogNewTimeHeadway", -1.0, false);
     230          86 :     double spacing = getFloatParam(v, oc, "toc.ogNewSpaceHeadway", -1.0, false);
     231          86 :     double changeRate = getFloatParam(v, oc, "toc.ogChangeRate", -1.0, false);
     232          86 :     double maxDecel = getFloatParam(v, oc, "toc.ogMaxDecel", -1.0, false);
     233             :     bool specifiedAny = false;
     234             : 
     235          86 :     if (changeRate == -1.0) {
     236             :         changeRate = DEFAULT_OPENGAP_CHANGERATE;
     237             :     } else {
     238             :         specifiedAny = true;
     239             :     }
     240          86 :     if (maxDecel == -1.0) {
     241             :         maxDecel = DEFAULT_OPENGAP_MAXDECEL;
     242             :     } else {
     243             :         specifiedAny = true;
     244             :     }
     245          86 :     if (specifiedAny && timegap == -1 && spacing == -1) {
     246           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."))
     247             :     }
     248          86 :     if (timegap == -1) {
     249             :         timegap = DEFAULT_OPENGAP_TIMEGAP;
     250             :     } else {
     251             :         specifiedAny = true;
     252             :     }
     253          86 :     if (spacing == -1) {
     254             :         spacing = DEFAULT_OPENGAP_SPACING;
     255             :     } else {
     256             :         specifiedAny = true;
     257             :     }
     258             : #ifdef DEBUG_TOC
     259             :     std::cout << "Parsed openGapParams: \n"
     260             :               << "  timegap=" << timegap
     261             :               << ", spacing=" << spacing
     262             :               << ", changeRate=" << changeRate
     263             :               << ", maxDecel=" << maxDecel
     264             :               << std::endl;
     265             : #endif
     266          86 :     return OpenGapParams(timegap, spacing, changeRate, maxDecel, specifiedAny);
     267             : }
     268             : 
     269             : // ---------------------------------------------------------------------------
     270             : // MSDevice_ToC-methods
     271             : // ---------------------------------------------------------------------------
     272          86 : MSDevice_ToC::MSDevice_ToC(SUMOVehicle& holder, const std::string& id, const std::string& outputFilename,
     273             :                            const std::string& manualType, const std::string& automatedType, SUMOTime responseTime, double recoveryRate,
     274             :                            double lcAbstinence, double initialAwareness, double mrmDecel,
     275             :                            double dynamicToCThreshold, double dynamicMRMProbability, double maxPreparationAccel,
     276          86 :                            bool mrmKeepRight, const std::string& mrmSafeSpot, SUMOTime mrmSafeSpotDuration, bool useColorScheme, OpenGapParams ogp) :
     277             :     MSVehicleDevice(holder, id),
     278          86 :     myManualTypeID(manualType),
     279          86 :     myAutomatedTypeID(automatedType),
     280          86 :     myResponseTime(responseTime),
     281          86 :     myRecoveryRate(recoveryRate),
     282          86 :     myLCAbstinence(lcAbstinence),
     283          86 :     myInitialAwareness(initialAwareness),
     284          86 :     myMRMDecel(mrmDecel),
     285          86 :     myCurrentAwareness(1.),
     286          86 :     myUseColorScheme(useColorScheme),
     287          86 :     myTriggerMRMCommand(nullptr),
     288          86 :     myTriggerToCCommand(nullptr),
     289          86 :     myRecoverAwarenessCommand(nullptr),
     290          86 :     myExecuteMRMCommand(nullptr),
     291          86 :     myPrepareToCCommand(nullptr),
     292          86 :     myOutputFile(nullptr),
     293             :     myEvents(),
     294             :     myEventLanes(),
     295             :     myEventXY(),
     296          86 :     myPreviousLCMode(-1),
     297          86 :     myOpenGapParams(ogp),
     298          86 :     myDynamicToCThreshold(dynamicToCThreshold),
     299          86 :     myMRMProbability(dynamicMRMProbability),
     300          86 :     myDynamicToCActive(dynamicToCThreshold > 0),
     301          86 :     myIssuedDynamicToC(false),
     302          86 :     myDynamicToCLane(-1),
     303          86 :     myMRMKeepRight(mrmKeepRight),
     304          86 :     myMRMSafeSpot(mrmSafeSpot),
     305          86 :     myMRMSafeSpotDuration(mrmSafeSpotDuration),
     306          86 :     myMaxPreparationAccel(maxPreparationAccel),
     307          86 :     myOriginalMaxAccel(-1) {
     308             :     // Take care! Holder is currently being constructed. Cast occurs before completion.
     309          86 :     myHolderMS = static_cast<MSVehicle*>(&holder);
     310             : 
     311          86 :     if (outputFilename != "") {
     312          70 :         myOutputFile = &OutputDevice::getDevice(outputFilename);
     313             :         // TODO: make xsd, include header
     314             :         // myOutputFile.writeXMLHeader("ToCDeviceLog", "ToCDeviceLog.xsd");
     315             :         if (createdOutputFiles.count(outputFilename) == 0) {
     316         136 :             myOutputFile->writeXMLHeader("ToCDeviceLog", "");
     317             :             createdOutputFiles.insert(outputFilename);
     318             :         }
     319             :     }
     320             : 
     321             :     // Check if the given vTypes for the ToC Device are vTypeDistributions
     322          86 :     MSVehicleControl& vehCtrl = MSNet::getInstance()->getVehicleControl();
     323          86 :     const bool automatedVTypeIsDist = vehCtrl.hasVTypeDistribution(myAutomatedTypeID);
     324          86 :     const bool manualVTypeIsDist = vehCtrl.hasVTypeDistribution(myManualTypeID);
     325             : 
     326             :     // Check if the vType of the holder matches one of the given vTypes
     327          86 :     std::string holderVTypeID = holder.getVehicleType().getID();
     328          86 :     if (holderVTypeID == myManualTypeID) {
     329           6 :         myState = ToCState::MANUAL;
     330          80 :     } else if (holderVTypeID == myAutomatedTypeID) {
     331          76 :         myState = ToCState::AUTOMATED;
     332           8 :     } else if (manualVTypeIsDist && vehCtrl.getVTypeDistributionMembership(holderVTypeID).count(myManualTypeID) > 0) {
     333             :         // Holder type id is from the given manual type distribution.
     334           0 :         myState = ToCState::MANUAL;
     335             :         myManualTypeID = holderVTypeID;
     336           6 :     } else if (automatedVTypeIsDist && vehCtrl.getVTypeDistributionMembership(holderVTypeID).count(myAutomatedTypeID) > 0) {
     337             :         // Holder type id is from the given automated type distribution.
     338           2 :         myState = ToCState::AUTOMATED;
     339             :         myAutomatedTypeID = holderVTypeID;
     340             :     } else {
     341           4 :         throw ProcessError("Vehicle type of vehicle '" + holder.getID() + "' ('" +
     342           6 :                            holder.getVehicleType().getID() + "') must coincide with manualType ('" +
     343           4 :                            manualType + "') or automatedType ('" + automatedType +
     344           4 :                            "') specified for its ToC-device (or drawn from the specified vTypeDistributions).");
     345             :     }
     346          84 :     if (!vehCtrl.hasVType(myAutomatedTypeID)) {
     347           4 :         throw ProcessError("The automated vehicle type '" + myAutomatedTypeID +
     348           8 :                            "' of vehicle '" + holder.getID() + "' is not known.");
     349             :     }
     350          82 :     if (!vehCtrl.hasVType(myManualTypeID)) {
     351           0 :         throw ProcessError("The manual vehicle type '" + myManualTypeID +
     352           0 :                            "' of vehicle '" + holder.getID() + "' is not known.");
     353             :     }
     354             : 
     355             :     // Eventually instantiate given vTypes from distributions
     356          82 :     if (myState == ToCState::MANUAL && automatedVTypeIsDist) {
     357           0 :         myAutomatedTypeID = vehCtrl.getVType(myAutomatedTypeID, MSRouteHandler::getParsingRNG())->getID();
     358          82 :     } else if (myState == ToCState::AUTOMATED && manualVTypeIsDist) {
     359           2 :         myManualTypeID = vehCtrl.getVType(myManualTypeID, MSRouteHandler::getParsingRNG())->getID();
     360             :     }
     361             : 
     362             :     // register at static instance container
     363          86 :     myInstances.insert(this);
     364          82 :     initColorScheme();
     365             : 
     366             : #ifdef DEBUG_TOC
     367             :     std::cout << "initialized device '" << id << "' with "
     368             :               << "outputFilename=" << outputFilename << ", "
     369             :               << "myManualType=" << myManualTypeID << ", "
     370             :               << "myAutomatedType=" << myAutomatedTypeID << ", "
     371             :               << "myResponseTime=" << myResponseTime << ", "
     372             :               << "myRecoveryRate=" << myRecoveryRate << ", "
     373             :               << "myInitialAwareness=" << myInitialAwareness << ", "
     374             :               << "myMRMDecel=" << myMRMDecel << ", "
     375             :               << "ogTimeHeadway=" << myOpenGapParams.newTimeHeadway << ", "
     376             :               << "ogSpaceHeadway=" << myOpenGapParams.newSpaceHeadway << ", "
     377             :               << "ogChangeRate=" << myOpenGapParams.changeRate << ", "
     378             :               << "ogMaxDecel=" << myOpenGapParams.maxDecel << ", "
     379             :               << "ogActive=" << myOpenGapParams.active << ", "
     380             :               << "myCurrentAwareness=" << myCurrentAwareness << ", "
     381             :               << "myState=" << _2string(myState) << std::endl;
     382             : #endif
     383             : 
     384             :     assert(myInitialAwareness <= 1.0 && myInitialAwareness >= 0.0);
     385          86 : }
     386             : 
     387             : 
     388             : 
     389             : void
     390          82 : MSDevice_ToC::initColorScheme() {
     391             :     //RGBColor(red, green, blue)
     392          82 :     myColorScheme[MANUAL] = MSNet::getInstance()->getVehicleControl().getVType(myManualTypeID)->getColor();
     393          82 :     myColorScheme[AUTOMATED] = MSNet::getInstance()->getVehicleControl().getVType(myAutomatedTypeID)->getColor();
     394          82 :     myColorScheme[PREPARING_TOC] = RGBColor(200, 200, 250); // light blue
     395          82 :     myColorScheme[MRM] = RGBColor(250, 50, 50); // red
     396          82 :     myColorScheme[RECOVERING] = RGBColor(250, 210, 150); // light yellow
     397          82 :     myColorScheme[UNDEFINED] = RGBColor(150, 150, 150); // gray
     398          82 : }
     399             : 
     400             : 
     401         164 : MSDevice_ToC::~MSDevice_ToC() {
     402             :     // unregister from static instance container
     403          82 :     myInstances.erase(this);
     404             :     // deschedule commands associated to this device
     405          82 :     if (myTriggerMRMCommand != nullptr) {
     406             :         myTriggerMRMCommand->deschedule();
     407             :     }
     408          82 :     if (myTriggerToCCommand != nullptr) {
     409             :         myTriggerToCCommand->deschedule();
     410             :     }
     411          82 :     if (myRecoverAwarenessCommand != nullptr) {
     412             :         myRecoverAwarenessCommand->deschedule();
     413             :     }
     414          82 :     if (myExecuteMRMCommand != nullptr) {
     415             :         myExecuteMRMCommand->deschedule();
     416           4 :         resetDeliberateLCs();
     417             :     }
     418          82 :     if (myPrepareToCCommand != nullptr) {
     419             :         myPrepareToCCommand->deschedule();
     420             :     }
     421         164 : }
     422             : 
     423             : void
     424        1002 : MSDevice_ToC::setAwareness(double value) {
     425        1002 :     if (value > 1.0 || value < 0.0) {
     426           0 :         std::stringstream ss;
     427           0 :         ss << "Truncating invalid value for awareness (" << value << ") to lie in [0,1].";
     428           0 :         WRITE_WARNING(ss.str());
     429             :         value = MAX2(0.0, MIN2(1.0, value));
     430           0 :     }
     431        1002 :     if (myCurrentAwareness >= myLCAbstinence && value < myLCAbstinence) {
     432             :         // Awareness is now below LC abstinence level -> prevent deliberate LCs
     433           8 :         deactivateDeliberateLCs();
     434         994 :     } else if (myCurrentAwareness < myLCAbstinence && value >= myLCAbstinence) {
     435             :         // Awareness is now above LC abstinence level -> allow deliberate LCs
     436           8 :         resetDeliberateLCs();
     437             :     }
     438        1002 :     myCurrentAwareness = value;
     439        1002 :     myHolderMS->getDriverState()->setAwareness(value);
     440        1002 : }
     441             : 
     442             : 
     443             : void
     444         510 : MSDevice_ToC::setState(ToCState state) {
     445             : #ifdef DEBUG_TOC
     446             :     std::cout << SIMTIME << " MSDevice_ToC::setState()" << std::endl;
     447             : #endif
     448         510 :     if (myState == state) {
     449             :         // No state change
     450             :         return;
     451             :     }
     452             : 
     453         510 :     if (myState == MRM) {
     454             :         // reset the vehicle's maxAccel
     455          70 :         myHolderMS->getSingularType().getCarFollowModel().setMaxAccel(myOriginalMaxAccel);
     456          70 :         resetDeliberateLCs();
     457         440 :     } else if (myState == PREPARING_TOC) {
     458         152 :         if (myOpenGapParams.active) {
     459             :             // Deactivate gap control at preparation phase end
     460           4 :             myHolderMS->getInfluencer().deactivateGapController();
     461             :         }
     462         152 :         if (state != MRM) {
     463             :             // Aborting preparation
     464          90 :             resetDeliberateLCs();
     465          90 :             myHolderMS->getSingularType().getCarFollowModel().setMaxAccel(myOriginalMaxAccel);
     466             :         }
     467         288 :     } else if (state == PREPARING_TOC || state == MRM) {
     468             : #ifdef DEBUG_TOC
     469             :         std::cout << "  Entering ToC preparation... " << std::endl;
     470             : #endif
     471             :         // Prevent lane changing during takeover preparation
     472         164 :         deactivateDeliberateLCs();
     473             :         // Store original value of maxAccel for restoring it after preparation phase
     474         164 :         myOriginalMaxAccel = myHolderMS->getCarFollowModel().getMaxAccel();
     475             :         // Impose acceleration limit during preparation
     476         164 :         myHolderMS->getSingularType().getCarFollowModel().setMaxAccel(MIN2(myMaxPreparationAccel, myOriginalMaxAccel));
     477             :     }
     478             : 
     479         510 :     if (myIssuedDynamicToC) {
     480             :         // Reset dynamic ToC flag
     481           6 :         myIssuedDynamicToC = false;
     482             :     }
     483             : 
     484         510 :     myState = state;
     485         510 :     if (myUseColorScheme) {
     486         510 :         setVehicleColor();
     487             :     }
     488             : }
     489             : 
     490             : void
     491         510 : MSDevice_ToC::setVehicleColor() {
     492         510 :     const SUMOVehicleParameter& p = myHolder.getParameter();
     493         510 :     p.color = myColorScheme[myState];
     494         510 :     p.parametersSet |= VEHPARS_COLOR_SET;
     495         510 : }
     496             : 
     497             : void
     498          16 : MSDevice_ToC::requestMRM() {
     499             :     // Remove any preparatory process
     500          16 :     descheduleToCPreparation();
     501             :     // .. and any recovery process
     502          16 :     descheduleRecovery();
     503             :     // ... and any pending ToC to manual
     504          16 :     descheduleToC();
     505             :     // Immediately trigger the MRM process
     506          16 :     triggerMRM(0);
     507          16 : }
     508             : 
     509             : 
     510             : void
     511         246 : MSDevice_ToC::requestToC(SUMOTime timeTillMRM, SUMOTime responseTime) {
     512             : #ifdef DEBUG_TOC
     513             :     std::cout << SIMTIME << " requestToC() for vehicle '" << myHolder.getID() << "', timeTillMRM=" << timeTillMRM << ", responseTime=" << responseTime << std::endl;
     514             : #endif
     515         246 :     if (myState == AUTOMATED) {
     516             :         // Initialize preparation phase
     517         152 :         if (responseTime == -1000) {
     518             :             // Sample response time from distribution
     519           8 :             const double sample = sampleResponseTime(STEPS2TIME(timeTillMRM));
     520             :             // this needs to be a separate line because TIME2STEPS may otherwise do two calls to sampleResponseTime
     521           8 :             responseTime = TIME2STEPS(sample);
     522             :         }
     523             : 
     524             :         // Schedule ToC Event
     525         152 :         myTriggerToCCommand = new WrappingCommand<MSDevice_ToC>(this, &MSDevice_ToC::triggerDownwardToC);
     526         152 :         MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(myTriggerToCCommand, SIMSTEP + responseTime);
     527             : 
     528             :         assert(myExecuteMRMCommand == nullptr);
     529             :         assert(myTriggerMRMCommand == nullptr);
     530         152 :         if (responseTime > timeTillMRM && myState != MRM) {
     531             :             // Schedule new MRM if driver response time is higher than permitted
     532         102 :             myTriggerMRMCommand = new WrappingCommand<MSDevice_ToC>(this, &MSDevice_ToC::triggerMRM);
     533         102 :             MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(myTriggerMRMCommand, SIMSTEP + timeTillMRM);
     534             :         }
     535             : 
     536             :         // Start ToC preparation process
     537         152 :         myPrepareToCCommand = new WrappingCommand<MSDevice_ToC>(this, &MSDevice_ToC::ToCPreparationStep);
     538         152 :         MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(myPrepareToCCommand, SIMSTEP + DELTA_T);
     539         152 :         setState(PREPARING_TOC);
     540         152 :         if (myOpenGapParams.active) {
     541             :             // Start gap controller
     542           4 :             double originalTau = myHolderMS->getCarFollowModel().getHeadwayTime();
     543           4 :             myHolderMS->getInfluencer().activateGapController(originalTau,
     544             :                     myOpenGapParams.newTimeHeadway, myOpenGapParams.newSpaceHeadway, -1,
     545             :                     myOpenGapParams.changeRate, myOpenGapParams.maxDecel);
     546             :         }
     547             :         // Record event
     548         152 :         if (generatesOutput()) {
     549         150 :             myEvents.push(std::make_pair(SIMSTEP, "TOR"));
     550         150 :             myEventLanes.push(std::make_pair(myHolder.getLane()->getID(), myHolder.getPositionOnLane())); // add lane and lanepos
     551         150 :             myEventXY.push(std::make_pair(myHolder.getPosition().x(), myHolder.getPosition().y()));       // add (x, y) position
     552             :         }
     553             :     } else {
     554             :         // Switch to automated mode is performed immediately
     555          94 :         if (timeTillMRM > 0) {
     556          76 :             std::stringstream ss;
     557         228 :             ss << "[t=" << SIMTIME << "] Positive transition time (" << STEPS2TIME(timeTillMRM) << "s.) for upward ToC of vehicle '" << myHolder.getID() << "' is ignored.";
     558          76 :             WRITE_WARNING(ss.str());
     559          76 :         }
     560          94 :         triggerUpwardToC(SIMSTEP + DELTA_T);
     561             :     }
     562         246 : }
     563             : 
     564             : 
     565             : SUMOTime
     566          74 : MSDevice_ToC::triggerMRM(SUMOTime /* t */) {
     567             : #ifdef DEBUG_TOC
     568             :     std::cout << SIMTIME << " triggerMRM() for vehicle '" << myHolder.getID() << "'" << std::endl;
     569             : #endif
     570             :     // Clear ongoing MRM
     571          74 :     descheduleMRM();
     572             : 
     573             :     // Start MRM process
     574          74 :     if (myMRMSafeSpot != "") {
     575           0 :         SUMOVehicleParameter::Stop stop;
     576           0 :         MSStoppingPlace* s = MSNet::getInstance()->getStoppingPlace(myMRMSafeSpot, SUMO_TAG_PARKING_AREA);
     577           0 :         if (s == nullptr) {
     578           0 :             WRITE_WARNINGF(TL("Ignoring unknown safe spot '%' for vehicle '%'."), myMRMSafeSpot, myHolder.getID());
     579             :         } else {
     580             :             stop.parkingarea = myMRMSafeSpot;
     581           0 :             stop.parking = ParkingType::OFFROAD;
     582           0 :             stop.lane = s->getLane().getID();
     583           0 :             stop.endPos = s->getEndLanePosition();
     584           0 :             stop.startPos = s->getBeginLanePosition();
     585           0 :             stop.duration = myMRMSafeSpotDuration;
     586           0 :             myHolderMS->getSingularType().setDecel(myMRMDecel);
     587             :             std::string error;
     588           0 :             if (!myHolder.addStop(stop, error)) {
     589           0 :                 WRITE_WARNING("Could not set safe spot '" + myMRMSafeSpot + "' for vehicle '" + myHolder.getID() + "'. " + error);
     590             :             }
     591             :         }
     592           0 :     } else {
     593          74 :         myExecuteMRMCommand = new WrappingCommand<MSDevice_ToC>(this, &MSDevice_ToC::MRMExecutionStep);
     594          74 :         MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(myExecuteMRMCommand, SIMSTEP + DELTA_T);
     595             :     }
     596          74 :     if (myState == MANUAL || myState == RECOVERING) {
     597           8 :         switchHolderType(myAutomatedTypeID);
     598             :     }
     599          74 :     setState(MRM);
     600          74 :     setAwareness(1.);
     601             : 
     602             :     // Record event
     603          74 :     if (generatesOutput()) {
     604          72 :         myEvents.push(std::make_pair(SIMSTEP, "MRM"));
     605          72 :         myEventLanes.push(std::make_pair(myHolder.getLane()->getID(), myHolder.getPositionOnLane())); // add lane and lanepos
     606          72 :         myEventXY.push(std::make_pair(myHolder.getPosition().x(), myHolder.getPosition().y()));       // add (x, y) position
     607             :     }
     608             : 
     609          74 :     return 0;
     610             : }
     611             : 
     612             : 
     613             : SUMOTime
     614          96 : MSDevice_ToC::triggerUpwardToC(SUMOTime /* t */) {
     615             : #ifdef DEBUG_TOC
     616             :     std::cout << SIMTIME << " triggerUpwardToC() for vehicle '" << myHolder.getID() << "'" << std::endl;
     617             : #endif
     618          96 :     descheduleToC();
     619             :     // Eventually stop ToC preparation process
     620          96 :     descheduleToCPreparation();
     621             :     // Eventually abort MRM
     622          96 :     descheduleMRM();
     623             :     // Eventually abort awareness recovery process
     624          96 :     descheduleRecovery();
     625             : 
     626          96 :     if (myState == MANUAL || myState == RECOVERING) {
     627          34 :         switchHolderType(myAutomatedTypeID);
     628             :     }
     629          96 :     setAwareness(1.);
     630          96 :     setState(AUTOMATED);
     631             : 
     632             :     // Record event
     633          96 :     if (generatesOutput()) {
     634          94 :         myEvents.push(std::make_pair(SIMSTEP, "ToCup"));
     635          94 :         myEventLanes.push(std::make_pair(myHolder.getLane()->getID(), myHolder.getPositionOnLane())); // add lane and lanepos
     636          94 :         myEventXY.push(std::make_pair(myHolder.getPosition().x(), myHolder.getPosition().y()));       // add (x, y) position
     637             :     }
     638             : 
     639          96 :     return 0;
     640             : }
     641             : 
     642             : 
     643             : SUMOTime
     644          98 : MSDevice_ToC::triggerDownwardToC(SUMOTime /* t */) {
     645             : #ifdef DEBUG_TOC
     646             :     std::cout << SIMTIME << " triggerDownwardToC() for vehicle '" << myHolder.getID() << "'" << std::endl;
     647             : #endif
     648          98 :     descheduleToC();
     649             :     // Eventually stop ToC preparation process
     650          98 :     descheduleToCPreparation();
     651             :     // Eventually abort MRM
     652          98 :     descheduleMRM();
     653             : 
     654             : #ifdef DEBUG_TOC
     655             :     std::cout << SIMTIME << " Initial awareness after ToC: " << myCurrentAwareness << std::endl;
     656             : #endif
     657             : 
     658             :     // Start awareness recovery process
     659          98 :     myRecoverAwarenessCommand = new WrappingCommand<MSDevice_ToC>(this, &MSDevice_ToC::awarenessRecoveryStep);
     660          98 :     MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(myRecoverAwarenessCommand, SIMSTEP + DELTA_T);
     661          98 :     setState(RECOVERING);
     662             : 
     663             :     // @todo: Sample initial awareness
     664          98 :     double initialAwareness = myInitialAwareness;
     665          98 :     setAwareness(initialAwareness);
     666             : 
     667          98 :     switchHolderType(myManualTypeID);
     668             : 
     669             :     // Record event
     670          98 :     if (generatesOutput()) {
     671          96 :         myEvents.push(std::make_pair(SIMSTEP, "ToCdown"));
     672          96 :         myEventLanes.push(std::make_pair(myHolder.getLane()->getID(), myHolder.getPositionOnLane())); // add lane and lanepos
     673          96 :         myEventXY.push(std::make_pair(myHolder.getPosition().x(), myHolder.getPosition().y()));       // add (x, y) position
     674             :     }
     675          98 :     return 0;
     676             : }
     677             : 
     678             : void
     679         268 : MSDevice_ToC::descheduleMRM() {
     680             :     // Eventually abort scheduled MRM
     681         268 :     if (myTriggerMRMCommand != nullptr) {
     682             :         myTriggerMRMCommand->deschedule();
     683         102 :         myTriggerMRMCommand = nullptr;
     684             :     }
     685             :     // Eventually abort ongoing MRM
     686         268 :     if (myExecuteMRMCommand != nullptr) {
     687             :         myExecuteMRMCommand->deschedule();
     688          70 :         resetDeliberateLCs();
     689          70 :         myExecuteMRMCommand = nullptr;
     690             :     }
     691         268 : }
     692             : 
     693             : 
     694             : void
     695         210 : MSDevice_ToC::descheduleToC() {
     696         210 :     if (myTriggerToCCommand != nullptr) {
     697             :         myTriggerToCCommand->deschedule();
     698         152 :         myTriggerToCCommand = nullptr;
     699             :     }
     700         210 : }
     701             : 
     702             : void
     703         268 : MSDevice_ToC::descheduleToCPreparation() {
     704             :     // Eventually stop ToC preparation process
     705         268 :     if (myPrepareToCCommand != nullptr) {
     706             :         myPrepareToCCommand->deschedule();
     707         152 :         if (myState != MRM) {
     708          94 :             resetDeliberateLCs();
     709             :         }
     710         152 :         myPrepareToCCommand = nullptr;
     711             :     }
     712         268 : }
     713             : 
     714             : void
     715         112 : MSDevice_ToC::descheduleRecovery() {
     716             :     // Eventually stop ToC preparation process
     717         112 :     if (myRecoverAwarenessCommand != nullptr) {
     718             :         myRecoverAwarenessCommand->deschedule();
     719           8 :         myRecoverAwarenessCommand = nullptr;
     720             :     }
     721         112 : }
     722             : 
     723             : 
     724             : void
     725         140 : MSDevice_ToC::switchHolderType(const std::string& targetTypeID) {
     726             : #ifdef DEBUG_TOC
     727             :     std::cout << SIMTIME << " Switching type of vehicle '" << myHolder.getID() << "' to '" << targetTypeID << "'" << std::endl;
     728             : #endif
     729         140 :     MSVehicleType* targetType = MSNet::getInstance()->getVehicleControl().getVType(targetTypeID);
     730         140 :     if (targetType == nullptr) {
     731           0 :         WRITE_ERRORF(TL("vType '%' for vehicle '%' is not known."), targetType->getID(), myHolder.getID());
     732           0 :         return;
     733             :     }
     734         140 :     myHolderMS->replaceVehicleType(targetType);
     735             : }
     736             : 
     737             : 
     738             : SUMOTime
     739        1588 : MSDevice_ToC::ToCPreparationStep(SUMOTime /* t */) {
     740             : #ifdef DEBUG_TOC
     741             :     std::cout << SIMTIME << " ToC preparation step for vehicle '" << myHolder.getID() << "'" << std::endl;
     742             : #endif
     743        1588 :     if (myState == PREPARING_TOC) {
     744        1530 :         return DELTA_T;
     745             :     } else {
     746             : #ifdef DEBUG_TOC
     747             :         std::cout << SIMTIME << " Aborting ToC preparation for vehicle '" << myHolder.getID() << "'" << std::endl;
     748             : #endif
     749          58 :         descheduleToCPreparation();
     750          58 :         return 0;
     751             :     }
     752             : }
     753             : 
     754             : 
     755             : SUMOTime
     756        2426 : MSDevice_ToC::MRMExecutionStep(SUMOTime t) {
     757        2426 :     deactivateDeliberateLCs();
     758        2426 :     const double currentSpeed = myHolderMS->getSpeed();
     759             : #ifdef DEBUG_TOC
     760             :     std::cout << SIMTIME << " MRM step for vehicle '" << myHolder.getID() << "', currentSpeed=" << currentSpeed << std::endl;
     761             : #endif
     762             : 
     763             :     // Induce slowdown with MRMDecel
     764             :     std::vector<std::pair<SUMOTime, double> > speedTimeLine;
     765        2426 :     const double nextSpeed = MAX2(0., currentSpeed - ACCEL2SPEED(myMRMDecel));
     766        2426 :     speedTimeLine.push_back(std::make_pair(t - DELTA_T, currentSpeed));
     767        2426 :     speedTimeLine.push_back(std::make_pair(t, nextSpeed));
     768        2426 :     myHolderMS->getInfluencer().setSpeedTimeLine(speedTimeLine);
     769             : 
     770        2426 :     if (myMRMKeepRight) {
     771             :         // Try to change to the right
     772             :         std::vector<std::pair<SUMOTime, int> > laneTimeLine;
     773          68 :         laneTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep(), 0));
     774          68 :         laneTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep() + 1, 0));
     775          68 :         myHolderMS->getInfluencer().setLaneTimeLine(laneTimeLine);
     776             : //      std::cout << "Keeping right..." << std::endl;
     777             :     }
     778             : 
     779        2426 :     if (myState == MRM) {
     780        2426 :         return DELTA_T;
     781             :     } else {
     782             : #ifdef DEBUG_TOC
     783             :         std::cout << SIMTIME << " Aborting MRM for vehicle '" << myHolder.getID() << "'" << std::endl;
     784             : #endif
     785           0 :         resetDeliberateLCs();
     786             :         return 0;
     787             :     }
     788             : }
     789             : 
     790             : 
     791             : SUMOTime
     792         734 : MSDevice_ToC::awarenessRecoveryStep(SUMOTime /* t */) {
     793             : #ifdef DEBUG_TOC
     794             :     std::cout << SIMTIME << " Awareness recovery step for vehicle '" << myHolder.getID() << "'" << std::endl;
     795             : #endif
     796             :     // Proceed with awareness recovery
     797         734 :     if (myCurrentAwareness < 1.0) {
     798        1378 :         setAwareness(MIN2(1.0, myCurrentAwareness + TS * myRecoveryRate));
     799             :     }
     800             : 
     801             : #ifdef DEBUG_TOC
     802             :     std::cout << SIMTIME << " currentAwareness = " << myCurrentAwareness << std::endl;
     803             : #endif
     804             : 
     805         734 :     const bool awarenessRecoveryCompleted = myCurrentAwareness == 1.0;
     806         734 :     if (awarenessRecoveryCompleted) {
     807             : #ifdef DEBUG_TOC
     808             :         std::cout << SIMTIME << " Awareness recovery completed for veh '" << myHolder.getID() << "'" << std::endl;
     809             : #endif
     810          90 :         myRecoverAwarenessCommand->deschedule();
     811          90 :         myRecoverAwarenessCommand = nullptr;
     812          90 :         setState(MANUAL);
     813          90 :         return 0;
     814             :     }
     815         644 :     return DELTA_T;
     816             : }
     817             : 
     818             : bool
     819       31262 : MSDevice_ToC::notifyMove(SUMOTrafficObject& /*veh*/,
     820             :                          double /*oldPos*/,
     821             :                          double /*newPos*/,
     822             :                          double /*newSpeed*/) {
     823       31262 :     if (myState == AUTOMATED && checkDynamicToC()) {
     824             :         // Initiate a ToC
     825             :         // Record event
     826           6 :         if (generatesOutput()) {
     827           6 :             myEvents.push(std::make_pair(SIMSTEP, "DYNTOR"));
     828           6 :             myEventLanes.push(std::make_pair(myHolder.getLane()->getID(), myHolder.getPositionOnLane())); // add lane and lanepos
     829           6 :             myEventXY.push(std::make_pair(myHolder.getPosition().x(), myHolder.getPosition().y()));       // add (x, y) position
     830             :         }
     831             :         // Leadtime for dynamic ToC is proportional to the time assumed for the dynamic ToC threshold
     832           6 :         const double leadTime = myDynamicToCThreshold * 1000 * DYNAMIC_TOC_LEADTIME_FACTOR;
     833           6 :         requestToC((SUMOTime) leadTime);
     834             :         // 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)
     835           6 :         myIssuedDynamicToC = true;
     836           6 :         myDynamicToCLane = myHolderMS->getLane()->getNumericalID();
     837       31256 :     } else if (myIssuedDynamicToC && myState == PREPARING_TOC && !checkDynamicToC()) {
     838             :         // Abort dynamic ToC, FIXME: This could abort an externally requested ToC in rare occasions... (needs test)
     839             :         // Record event
     840           2 :         if (generatesOutput()) {
     841           2 :             myEvents.push(std::make_pair(SIMSTEP, "DYNTOR"));
     842           2 :             myEventLanes.push(std::make_pair(myHolder.getLane()->getID(), myHolder.getPositionOnLane())); // add lane and lanepos
     843           2 :             myEventXY.push(std::make_pair(myHolder.getPosition().x(), myHolder.getPosition().y()));       // add (x, y) position
     844             :         }
     845             :         // NOTE: This should not occur if lane changing is prevented during ToC preparation...
     846             :         // TODO: Reset response time to the original value (unnecessary if re-sampling for each call to requestToC)
     847           2 :         triggerUpwardToC(0);
     848             :     }
     849       31262 :     return true;
     850             : }
     851             : 
     852             : std::string
     853       87894 : MSDevice_ToC::getParameter(const std::string& key) const {
     854       87894 :     if (key == "manualType") {
     855             :         return myManualTypeID;
     856       84334 :     } else if (key == "automatedType") {
     857             :         return myAutomatedTypeID;
     858       80774 :     } else if (key == "responseTime") {
     859        3560 :         return toString(STEPS2TIME(myResponseTime));
     860       77214 :     } else if (key == "recoveryRate") {
     861        3560 :         return toString(myRecoveryRate);
     862       73654 :     } else if (key == "initialAwareness") {
     863        3560 :         return toString(myInitialAwareness);
     864       70094 :     } else if (key == "mrmDecel") {
     865        3560 :         return toString(myMRMDecel);
     866       66534 :     } else if (key == "currentAwareness") {
     867       30978 :         return toString(myCurrentAwareness);
     868       35556 :     } else if (key == "lcAbstinence") {
     869          20 :         return toString(myLCAbstinence);
     870       35536 :     } else if (key == "state") {
     871       31478 :         return _2string(myState);
     872        4058 :     } else if (key == "holder") {
     873        3560 :         return myHolder.getID();
     874         498 :     } else if (key == "hasDynamicToC") {
     875           0 :         return toString(myDynamicToCActive);
     876         498 :     } else if (key == "dynamicToCThreshold") {
     877         428 :         return toString(myDynamicToCThreshold);
     878          70 :     } else if (key == "dynamicMRMProbability") {
     879          20 :         return toString(myMRMProbability);
     880          50 :     } else if (key == "mrmKeepRight") {
     881          20 :         return toString(myMRMKeepRight);
     882          30 :     } else if (key == "mrmSafeSpot") {
     883             :         return myMRMSafeSpot;
     884          30 :     } else if (key == "mrmSafeSpotDuration") {
     885           0 :         return toString(STEPS2TIME(myMRMSafeSpotDuration));
     886          30 :     } else if (key == "maxPreparationAccel") {
     887          20 :         return toString(myMaxPreparationAccel);
     888          10 :     } else if (key == "ogNewTimeHeadway") {
     889           2 :         return toString(myOpenGapParams.newTimeHeadway);
     890           8 :     } else if (key == "ogNewSpaceHeadway") {
     891           4 :         return toString(myOpenGapParams.newSpaceHeadway);
     892           4 :     } else if (key == "ogChangeRate") {
     893           2 :         return toString(myOpenGapParams.changeRate);
     894           2 :     } else if (key == "ogMaxDecel") {
     895           2 :         return toString(myOpenGapParams.maxDecel);
     896             :     }
     897           0 :     throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
     898             : }
     899             : 
     900             : 
     901             : void
     902         264 : MSDevice_ToC::setParameter(const std::string& key, const std::string& value) {
     903             : #ifdef DEBUG_TOC
     904             :     std::cout << SIMTIME << " MSDevice_ToC::setParameter(key=" << key << ", value=" << value << ")" << std::endl;
     905             : #endif
     906         264 :     if (key == "manualType") {
     907           0 :         myManualTypeID = value;
     908           0 :         myColorScheme[MANUAL] = MSNet::getInstance()->getVehicleControl().getVType(myManualTypeID)->getColor();
     909           0 :         if (myState == MANUAL) {
     910           0 :             switchHolderType(value);
     911             :         }
     912         264 :     } else if (key == "automatedType") {
     913           0 :         myAutomatedTypeID = value;
     914           0 :         myColorScheme[AUTOMATED] = MSNet::getInstance()->getVehicleControl().getVType(myAutomatedTypeID)->getColor();
     915           0 :         if (myState == AUTOMATED || myState == PREPARING_TOC || myState == MRM) {
     916           0 :             switchHolderType(value);
     917             :         }
     918         264 :     } else if (key == "responseTime") {
     919           0 :         myResponseTime = TIME2STEPS(StringUtils::toDouble(value));
     920         264 :     } else if (key == "recoveryRate") {
     921           0 :         myRecoveryRate = StringUtils::toDouble(value);
     922         264 :     } else if (key == "initialAwareness") {
     923           0 :         myInitialAwareness = StringUtils::toDouble(value);
     924         264 :     } else if (key == "lcAbstinence") {
     925           0 :         myLCAbstinence = StringUtils::toDouble(value);
     926           0 :         if (isManuallyDriven()) {
     927           0 :             setAwareness(myCurrentAwareness); // to eventually trigger LC-prevention
     928             :         }
     929         264 :     } else if (key == "currentAwareness") {
     930           0 :         if (isManuallyDriven()) {
     931           0 :             setAwareness(StringUtils::toDouble(value));
     932             :         } else {
     933           0 :             WRITE_WARNING(TL("Setting device.toc.currentAwareness during automated mode has no effect."))
     934             :         }
     935         264 :     } else if (key == "mrmDecel") {
     936           0 :         myMRMDecel = StringUtils::toDouble(value);
     937         264 :     } else if (key == "requestToC") {
     938             :         // setting this magic parameter gives the interface for inducing a ToC
     939         240 :         const SUMOTime timeTillMRM = TIME2STEPS(StringUtils::toDouble(value));
     940         240 :         requestToC(timeTillMRM, myResponseTime);
     941          24 :     } else if (key == "requestMRM") {
     942             :         // setting this magic parameter gives the interface for inducing an MRM
     943          16 :         requestMRM();
     944           8 :     } else if (key == "awareness") {
     945             :         // setting this magic parameter gives the interface for setting the driverstate's awareness
     946           0 :         setAwareness(StringUtils::toDouble(value));
     947           8 :     } else if (key == "dynamicToCThreshold") {
     948           0 :         const double newValue = StringUtils::toDouble(value);
     949           0 :         if (newValue < 0) {
     950           0 :             WRITE_WARNINGF(TL("Value of dynamicToCThreshold must be non-negative. (Given value % for vehicle % is ignored)"), value, myHolderMS->getID());
     951           0 :         } else if (newValue == 0) {
     952           0 :             myDynamicToCThreshold = newValue;
     953           0 :             myDynamicToCActive = false;
     954             :         } else {
     955           0 :             myDynamicToCThreshold = newValue;
     956           0 :             myDynamicToCActive = true;
     957             :         }
     958           8 :     } else if (key == "dynamicMRMProbability") {
     959           0 :         const double newValue = StringUtils::toDouble(value);
     960           0 :         if (newValue < 0) {
     961           0 :             WRITE_WARNINGF(TL("Value of dynamicMRMProbability must be non-negative. (Given value % for vehicle % is ignored)"), value, myHolderMS->getID());
     962             :         } else {
     963           0 :             myMRMProbability = newValue;
     964             :         }
     965           8 :     } else if (key == "mrmKeepRight")  {
     966           0 :         const bool newValue = StringUtils::toBool(value);
     967           0 :         myMRMKeepRight = newValue;
     968           8 :     } else if (key == "mrmSafeSpot") {
     969           0 :         myMRMSafeSpot = value;
     970           8 :     } else if (key == "mrmSafeSpotDuration") {
     971           0 :         myMRMSafeSpotDuration = TIME2STEPS(StringUtils::toDouble(value));
     972           8 :     } else if (key == "maxPreparationAccel") {
     973           0 :         const double newValue = StringUtils::toDouble(value);
     974           0 :         if (newValue < 0) {
     975           0 :             WRITE_WARNINGF(TL("Value of maxPreparationAccel must be non-negative. (Given value % for vehicle % is ignored)"), value, myHolderMS->getID());
     976             :         } else {
     977           0 :             myMaxPreparationAccel = newValue;
     978             :         }
     979           8 :     } else if (key == "ogNewTimeHeadway") {
     980           2 :         const double newValue = StringUtils::toDouble(value);
     981           2 :         myOpenGapParams.newTimeHeadway = newValue;
     982           2 :         myOpenGapParams.active = true;
     983           6 :     } else if (key == "ogNewSpaceHeadway") {
     984           2 :         const double newValue = StringUtils::toDouble(value);
     985           2 :         myOpenGapParams.newSpaceHeadway = newValue;
     986           2 :         myOpenGapParams.active = true;
     987           4 :     } else if (key == "ogChangeRate") {
     988           2 :         const double newValue = StringUtils::toDouble(value);
     989           2 :         myOpenGapParams.changeRate = newValue;
     990           2 :         myOpenGapParams.active = true;
     991           2 :     } else if (key == "ogMaxDecel") {
     992           2 :         const double newValue = StringUtils::toDouble(value);
     993           2 :         myOpenGapParams.maxDecel = newValue;
     994           2 :         myOpenGapParams.active = true;
     995             :     } else {
     996           0 :         throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
     997             :     }
     998         264 : }
     999             : 
    1000             : 
    1001             : MSDevice_ToC::ToCState
    1002           0 : MSDevice_ToC::_2ToCState(const std::string& str) {
    1003           0 :     if (str == "UNDEFINED") {
    1004             :         return UNDEFINED;
    1005           0 :     } else if (str == "MANUAL") {
    1006             :         return MANUAL;
    1007           0 :     } else if (str == "AUTOMATED") {
    1008             :         return AUTOMATED;
    1009           0 :     } else if (str == "PREPARING_TOC") {
    1010             :         return PREPARING_TOC;
    1011           0 :     } else if (str == "MRM") {
    1012             :         return MRM;
    1013           0 :     } else if (str == "RECOVERING") {
    1014             :         return RECOVERING;
    1015             :     } else {
    1016           0 :         WRITE_WARNINGF(TL("Unknown ToCState '%'"), str);
    1017           0 :         return UNDEFINED;
    1018             :     }
    1019             : }
    1020             : 
    1021             : 
    1022             : std::string
    1023       31478 : MSDevice_ToC::_2string(ToCState state) {
    1024       31478 :     if (state == UNDEFINED) {
    1025           0 :         return "UNDEFINED";
    1026             :     } else if (state == MANUAL) {
    1027       17704 :         return "MANUAL";
    1028             :     } else if (state == AUTOMATED) {
    1029        8740 :         return "AUTOMATED";
    1030             :     } else if (state == PREPARING_TOC) {
    1031        1762 :         return "PREPARING_TOC";
    1032             :     } else if (state == MRM) {
    1033        2508 :         return "MRM";
    1034             :     } else if (state == RECOVERING) {
    1035         764 :         return "RECOVERING";
    1036             :     } else {
    1037           0 :         WRITE_WARNINGF(TL("Unknown ToCState '%'"), toString(state));
    1038           0 :         return toString(state);
    1039             :     }
    1040             : }
    1041             : 
    1042             : 
    1043             : void
    1044       30914 : MSDevice_ToC::writeOutput() {
    1045       30914 :     if (!generatesOutput()) {
    1046             :         assert(myEvents.empty());
    1047             :         return;
    1048             :     }
    1049       31328 :     while (!myEvents.empty()) {
    1050             :         const std::pair<SUMOTime, std::string> e = myEvents.front(); // make a copy, it is used after pop
    1051             :         const std::pair<std::string, double>& l = myEventLanes.front();
    1052             :         const std::pair<double, double>& p = myEventXY.front();
    1053         414 :         myOutputFile->openTag(e.second);
    1054        1242 :         myOutputFile->writeAttr("id", myHolder.getID()).writeAttr("t", STEPS2TIME(e.first));
    1055        1242 :         myOutputFile->writeAttr("lane", l.first).writeAttr("lanePos", l.second);
    1056        1242 :         myOutputFile->writeAttr("x", p.first).writeAttr("y", p.second);
    1057         828 :         myOutputFile->closeTag();
    1058             :         myEvents.pop();
    1059             :         myEventLanes.pop();
    1060             :         myEventXY.pop();
    1061             : 
    1062         414 :         if (e.second.compare("DYNTOR") == 0 && !myEvents.empty()) { // skip "TOR" events if duplicate of "DYNTOR"
    1063             :             std::pair<SUMOTime, std::string>& eNext = myEvents.front();
    1064           8 :             if (eNext.second.compare("TOR") == 0 && eNext.first == e.first) {
    1065             :                 myEvents.pop();
    1066             :                 myEventLanes.pop();
    1067             :                 myEventXY.pop();
    1068             :             }
    1069             :         }
    1070             :     }
    1071             : }
    1072             : 
    1073             : 
    1074             : void
    1075       35160 : MSDevice_ToC::cleanup() {
    1076             :     // Close xml bodies for all existing files
    1077             :     // TODO: Check if required
    1078       35226 :     for (auto& fn : createdOutputFiles) {
    1079          66 :         OutputDevice* file = &OutputDevice::getDevice(fn);
    1080         132 :         file->closeTag();
    1081             :     }
    1082       35160 : }
    1083             : 
    1084             : 
    1085             : void
    1086         336 : MSDevice_ToC::resetDeliberateLCs() {
    1087         336 :     if (myPreviousLCMode != -1) {
    1088         170 :         myHolderMS->getInfluencer().setLaneChangeMode(myPreviousLCMode);
    1089             : #ifdef DEBUG_TOC
    1090             :         std::cout << SIMTIME << " MSDevice_ToC::resetLCMode() restoring LC Mode of vehicle '" << myHolder.getID() << "' to " << myPreviousLCMode << std::endl;
    1091             : #endif
    1092             :     }
    1093         336 :     myPreviousLCMode = -1;
    1094         336 : }
    1095             : 
    1096             : 
    1097             : void
    1098        2598 : MSDevice_ToC::deactivateDeliberateLCs() {
    1099        2598 :     const int lcModeHolder = myHolderMS->getInfluencer().getLaneChangeMode();
    1100        2598 :     if (lcModeHolder != LCModeMRM) {
    1101         170 :         myPreviousLCMode = lcModeHolder;
    1102             : #ifdef DEBUG_TOC
    1103             :         std::cout << SIMTIME << " MSDevice_ToC::setLCModeMRM() setting LC Mode of vehicle '" << myHolder.getID()
    1104             :                   << "' from " << myPreviousLCMode << " to " << LCModeMRM << std::endl;
    1105             : #endif
    1106         170 :         myHolderMS->getInfluencer().setLaneChangeMode(LCModeMRM);
    1107             :     }
    1108        2598 : }
    1109             : 
    1110             : bool
    1111           0 : MSDevice_ToC::isManuallyDriven() {
    1112           0 :     return (myState == MANUAL || myState == RECOVERING);
    1113             : }
    1114             : 
    1115             : bool
    1116           0 : MSDevice_ToC::isAutomated() {
    1117           0 :     return (myState == AUTOMATED || myState == PREPARING_TOC || myState == MRM);
    1118             : }
    1119             : 
    1120             : bool
    1121        8610 : MSDevice_ToC::checkDynamicToC() {
    1122             : #ifdef DEBUG_DYNAMIC_TOC
    1123             :     std::cout << SIMTIME << " # MSDevice_ToC::checkDynamicToC() for veh '" << myHolder.getID() << "'" << std::endl;
    1124             : #endif
    1125        8610 :     if (!myDynamicToCActive) {
    1126             :         return false;
    1127             :     }
    1128             :     // The vehicle's current lane
    1129         466 :     const MSLane* currentLane = myHolderMS->getLane();
    1130             : 
    1131         466 :     if (currentLane->isInternal()) {
    1132             :         // Don't start or abort dynamic ToCs on internal lanes
    1133           2 :         return myIssuedDynamicToC;
    1134             :     }
    1135             : 
    1136         464 :     if (myIssuedDynamicToC) {
    1137             : #ifdef DEBUG_DYNAMIC_TOC
    1138             :         std::cout << SIMTIME << " Dynamic ToC is ongoing." << std::endl;
    1139             : #endif
    1140             :         // Dynamic ToC in progress. Resist to aborting it if lane was not changed.
    1141          52 :         if (myDynamicToCLane == currentLane->getNumericalID()) {
    1142             :             return true;
    1143             :         }
    1144             :     }
    1145             :     // Length for which the current route can be followed
    1146         414 :     const std::vector<MSVehicle::LaneQ>& bestLanes = myHolderMS->getBestLanes();
    1147             :     // Maximal distance for route continuation without LCs over the possible start lanes
    1148             :     double maximalContinuationDistance = 0;
    1149             :     // Distance for route continuation without LCs from the vehicle's current lane
    1150             :     double continuationDistanceOnCurrent = 0;
    1151             :     // Lane of the next stop
    1152             :     const MSLane* nextStopLane = nullptr;
    1153             : 
    1154         414 :     if (myHolderMS->hasStops()) {
    1155         158 :         nextStopLane = myHolderMS->getNextStop().lane;
    1156             :     }
    1157        1056 :     for (auto& i : bestLanes) {
    1158         800 :         maximalContinuationDistance = MAX2(maximalContinuationDistance, i.length);
    1159         800 :         if (currentLane == i.lane) {
    1160         414 :             if (myHolderMS->hasStops()) {
    1161             :                 // Check if the next stop lies on the route continuation from the current lane
    1162         158 :                 for (MSLane* l : i.bestContinuations) {
    1163         158 :                     if (l == nextStopLane) {
    1164             : #ifdef DEBUG_DYNAMIC_TOC
    1165             :                         std::cout << SIMTIME << " Stop found on the route continuation from the current lane. => No ToC" << std::endl;
    1166             : #endif
    1167             :                         // Stop found on the route continuation from the current lane => no ToC necessary
    1168             :                         return false;
    1169             :                     }
    1170             :                 }
    1171             :             }
    1172         256 :             continuationDistanceOnCurrent = i.length;
    1173             :         }
    1174             :     }
    1175         256 :     if (continuationDistanceOnCurrent == maximalContinuationDistance) {
    1176             :         // There is no better lane than the current, hence no desire to change lanes,
    1177             :         // which the driver could pursue better than the automation => no reason for ToC.
    1178             :         return false;
    1179             :     }
    1180         182 :     const double distFromCurrent = continuationDistanceOnCurrent - myHolderMS->getPositionOnLane();
    1181         182 :     const double MRMDist = 0.5 * myHolderMS->getSpeed() * myHolderMS->getSpeed() / MAX2(myMRMDecel, 0.0001);
    1182         182 :     double distThreshold = myHolderMS->getSpeed() * myDynamicToCThreshold + MRMDist;
    1183             : #ifdef DEBUG_DYNAMIC_TOC
    1184             :     std::cout << "  speed=" << myHolderMS->getSpeed()
    1185             :               << ", distFromCurrent=" << distFromCurrent
    1186             :               << ", maximal dist=" << maximalContinuationDistance - myHolderMS->getPositionOnLane()
    1187             :               << ", distThreshold=" << distThreshold
    1188             :               << std::endl;
    1189             : #endif
    1190             : 
    1191         182 :     if (myIssuedDynamicToC) {
    1192             :         // In case of an ongoing ToC, add an additional resistance to abort it.
    1193             :         // (The lane-check above does not capture lanes subsequent to the dynamic ToC lane)
    1194           0 :         distThreshold *= DYNAMIC_TOC_ABORT_RESISTANCE_FACTOR;
    1195             :     }
    1196             : 
    1197         182 :     if (distFromCurrent < distThreshold) {
    1198             :         // TODO: Make this more sophisticated in dealing with low speeds/stops and route ends
    1199             : #ifdef DEBUG_DYNAMIC_TOC
    1200             :         std::cout << SIMTIME << "  * distAlongBest is below threshold! *" << std::endl;
    1201             : #endif
    1202           6 :         return true;
    1203             :     }
    1204             : 
    1205             :     return false;
    1206             : }
    1207             : 
    1208             : double
    1209           8 : MSDevice_ToC::sampleResponseTime(double leadTime) const {
    1210             : #ifdef DEBUG_DYNAMIC_TOC
    1211             :     std::cout << "sampleResponseTime() leadTime=" << leadTime << std::endl;
    1212             : #endif
    1213             :     const double mean = responseTimeMean(leadTime);
    1214           8 :     const double var = interpolateVariance(leadTime, myMRMProbability);
    1215           8 :     double rt = RandHelper::randNorm(mean, var, &myResponseTimeRNG);
    1216             : #ifdef DEBUG_DYNAMIC_TOC
    1217             :     std::cout << "  mean=" << mean << ", variance=" << var << " => sampled responseTime=" << rt << std::endl;
    1218             : #endif
    1219             :     int it_count = 0;
    1220           8 :     while (rt < 0 && it_count < MAX_RESPONSETIME_SAMPLE_TRIES) {
    1221           0 :         rt = RandHelper::randNorm(mean, var, &myResponseTimeRNG);
    1222           0 :         it_count++;
    1223             :     }
    1224           8 :     if (rt < 0) {
    1225             :         // Didn't generate a positive random response time => use mean
    1226             :         rt = mean;
    1227             :     }
    1228           8 :     return rt;
    1229             : }
    1230             : 
    1231             : double
    1232           8 : MSDevice_ToC::interpolateVariance(double leadTime, double pMRM) {
    1233             : #ifdef DEBUG_DYNAMIC_TOC
    1234             :     std::cout << "interpolateVariance() leadTime=" << leadTime << ", pMRM=" << pMRM << std::endl;
    1235             : #endif
    1236             :     // Calculate indices for surrounding values in lookup tables
    1237             : 
    1238             :     // Find largest p_{i-1} < pMRM < p_{i}
    1239             :     const auto pi = std::lower_bound(lookupResponseTimeMRMProbs.begin(), lookupResponseTimeMRMProbs.end(), pMRM);
    1240           8 :     if (pi == lookupResponseTimeMRMProbs.end()) {
    1241             :         // requested probability lies outside lookup table.
    1242             :         // => return maximal variance value
    1243             :         return MAX_RESPONSETIME_VARIANCE;
    1244             :     }
    1245           8 :     const size_t pi1 = pi - lookupResponseTimeMRMProbs.begin();
    1246             :     assert(pi1 > 0);
    1247           8 :     const size_t pi0 = pi1 - 1;
    1248           8 :     const double cp = (pMRM - * (pi - 1)) / (*pi - * (pi - 1));
    1249             : 
    1250             : #ifdef DEBUG_DYNAMIC_TOC
    1251             :     std::cout << " p[=" << pi0 << "]=" << *(pi - 1) << ", p[=" << pi1 << "]=" << *pi << " => cp=" << cp << std::endl;
    1252             : #endif
    1253             : 
    1254             :     // Find largest p_{i-1} < pMRM < p_{i}
    1255             :     auto li = std::lower_bound(lookupResponseTimeLeadTimes.begin(), lookupResponseTimeLeadTimes.end(), leadTime);
    1256           8 :     if (li == lookupResponseTimeLeadTimes.begin()) {
    1257             :         // Given lead time smaller than minimal lookup-value.
    1258             :         // Use minimal value from lookup table instead
    1259           0 :         leadTime = *li;
    1260             :         li = lookupResponseTimeLeadTimes.begin() + 1;
    1261           8 :     } else if (li == lookupResponseTimeLeadTimes.end()) {
    1262             :         // Given leadTime exceeds values in lookup table
    1263             :         // => induce extrapolation
    1264             :         li--;
    1265             :     }
    1266             :     const size_t li1 = li - lookupResponseTimeLeadTimes.begin();
    1267             :     const size_t li0 = li1 - 1;
    1268           8 :     const double cl = (leadTime - * (li - 1)) / (*li - * (li - 1));
    1269             : 
    1270             : #ifdef DEBUG_DYNAMIC_TOC
    1271             :     std::cout << " l[=" << li0 << "]=" << *(li - 1) << ", l[=" << li1 << "]=" << *li << " => cp=" << cl << std::endl;
    1272             : #endif
    1273             : 
    1274             :     // 2D interpolation for variance
    1275             :     // First, interpolate (or extrapolate) variances along leadTimes
    1276           8 :     const double var00 = lookupResponseTimeVariances[pi0][li0];
    1277           8 :     const double var01 = lookupResponseTimeVariances[pi0][li1];
    1278           8 :     const double var10 = lookupResponseTimeVariances[pi1][li0];
    1279           8 :     const double var11 = lookupResponseTimeVariances[pi1][li1];
    1280           8 :     const double var_0 = var00 + (var01 - var00) * cl;
    1281           8 :     const double var_1 = var10 + (var11 - var10) * cl;
    1282             :     // From these, interpolate along the pMRM-axis
    1283           8 :     const double var = var_0 + (var_1 - var_0) * cp;
    1284             : #ifdef DEBUG_DYNAMIC_TOC
    1285             :     std::cout << " var00=" << var00 << ", var01=" << var01 << " var10=" << var10 << ", var11=" << var11
    1286             :               << " var_0=" << var_0 << ", var_1=" << var_1 << ", var=" << var << std::endl;
    1287             : #endif
    1288           8 :     return var;
    1289             : }
    1290             : 
    1291             : // Grid of the response time distribution.
    1292             : // Generated by the script generateResponseTimeDistributions.py, see Appendix to TransAID Deliverable 3.1v2.
    1293             : // Probability for an MRM to occur (start with 0.0, end with 0.5)
    1294             : 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};
    1295             : // Lead time grid
    1296             : 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};
    1297             : 
    1298             : // Variances of the response time distribution.
    1299             : std::vector<std::vector<double> > MSDevice_ToC::lookupResponseTimeVariances = {
    1300             :     {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},
    1301             :     {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},
    1302             :     {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},
    1303             :     {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},
    1304             :     {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},
    1305             :     {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},
    1306             :     {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},
    1307             :     {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},
    1308             :     {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},
    1309             :     {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},
    1310             :     {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},
    1311             : };
    1312             : 
    1313             : 
    1314             : /****************************************************************************/

Generated by: LCOV version 1.14