diff --git a/docs/inputs.rst b/docs/inputs.rst index 231681f158f..713b443165f 100755 --- a/docs/inputs.rst +++ b/docs/inputs.rst @@ -56,34 +56,101 @@ Mode choice parameters :: beam.agentsim.agents.modalBehaviors.modeChoiceClass = "ModeChoiceMultinomialLogit" + beam.agentsim.agents.modalBehaviors.maximumNumberOfReplanningAttempts = 3 beam.agentsim.agents.modalBehaviors.defaultValueOfTime = 8.0 + beam.agentsim.agents.modalBehaviors.minimumValueOfTime = 7.25 + beam.agentsim.agents.modalBehaviors.modeVotMultiplier.transit = 1.0 + beam.agentsim.agents.modalBehaviors.modeVotMultiplier.bike = 1.0 + beam.agentsim.agents.modalBehaviors.modeVotMultiplier.walk = 1.0 + beam.agentsim.agents.modalBehaviors.modeVotMultiplier.rideHail = 1.0 + beam.agentsim.agents.modalBehaviors.modeVotMultiplier.rideHailPooled = 1.0 + beam.agentsim.agents.modalBehaviors.modeVotMultiplier.rideHailTransit = 1.0 + beam.agentsim.agents.modalBehaviors.modeVotMultiplier.waiting = 1.0 + beam.agentsim.agents.modalBehaviors.modeVotMultiplier.CAV = 1.0 + beam.agentsim.agents.modalBehaviors.modeVotMultiplier.drive = 1.0 + beam.agentsim.agents.modalBehaviors.overrideAutomationLevel = 1 + beam.agentsim.agents.modalBehaviors.overrideAutomationForVOTT = false + beam.agentsim.agents.modalBehaviors.poolingMultiplier.Level5 = 1.0 + beam.agentsim.agents.modalBehaviors.poolingMultiplier.Level4 = 1.0 + beam.agentsim.agents.modalBehaviors.poolingMultiplier.Level3 = 1.0 + beam.agentsim.agents.modalBehaviors.poolingMultiplier.LevelLE2 = 1.0 + beam.agentsim.agents.modalBehaviors.highTimeSensitivity.highCongestion.highwayFactor.Level5 = 1.0 + beam.agentsim.agents.modalBehaviors.highTimeSensitivity.highCongestion.nonHighwayFactor.Level5 = 1.0 + beam.agentsim.agents.modalBehaviors.highTimeSensitivity.lowCongestion.highwayFactor.Level5 = 1.0 + beam.agentsim.agents.modalBehaviors.highTimeSensitivity.lowCongestion.nonHighwayFactor.Level5 = 1.0 + beam.agentsim.agents.modalBehaviors.lowTimeSensitivity.highCongestion.highwayFactor.Level5 = 1.0 + beam.agentsim.agents.modalBehaviors.lowTimeSensitivity.highCongestion.nonHighwayFactor.Level5 = 1.0 + beam.agentsim.agents.modalBehaviors.lowTimeSensitivity.lowCongestion.highwayFactor.Level5 = 1.0 + beam.agentsim.agents.modalBehaviors.lowTimeSensitivity.lowCongestion.nonHighwayFactor.Level5 = 1.0 + beam.agentsim.agents.modalBehaviors.highTimeSensitivity.highCongestion.highwayFactor.Level4 = 1.0 + beam.agentsim.agents.modalBehaviors.highTimeSensitivity.highCongestion.nonHighwayFactor.Level4 = 1.0 + beam.agentsim.agents.modalBehaviors.highTimeSensitivity.lowCongestion.highwayFactor.Level4 = 1.0 + beam.agentsim.agents.modalBehaviors.highTimeSensitivity.lowCongestion.nonHighwayFactor.Level4 = 1.0 + beam.agentsim.agents.modalBehaviors.lowTimeSensitivity.highCongestion.highwayFactor.Level4 = 1.0 + beam.agentsim.agents.modalBehaviors.lowTimeSensitivity.highCongestion.nonHighwayFactor.Level4 = 1.0 + beam.agentsim.agents.modalBehaviors.lowTimeSensitivity.lowCongestion.highwayFactor.Level4 = 1.0 + beam.agentsim.agents.modalBehaviors.lowTimeSensitivity.lowCongestion.nonHighwayFactor.Level4 = 1.0 + beam.agentsim.agents.modalBehaviors.highTimeSensitivity.highCongestion.highwayFactor.Level3 = 1.0 + beam.agentsim.agents.modalBehaviors.highTimeSensitivity.highCongestion.nonHighwayFactor.Level3 = 1.0 + beam.agentsim.agents.modalBehaviors.highTimeSensitivity.lowCongestion.highwayFactor.Level3 = 1.0 + beam.agentsim.agents.modalBehaviors.highTimeSensitivity.lowCongestion.nonHighwayFactor.Level3 = 1.0 + beam.agentsim.agents.modalBehaviors.lowTimeSensitivity.highCongestion.highwayFactor.Level3 = 1.0 + beam.agentsim.agents.modalBehaviors.lowTimeSensitivity.highCongestion.nonHighwayFactor.Level3 = 1.0 + beam.agentsim.agents.modalBehaviors.lowTimeSensitivity.lowCongestion.highwayFactor.Level3 = 1.0 + beam.agentsim.agents.modalBehaviors.lowTimeSensitivity.lowCongestion.nonHighwayFactor.Level3 = 1.0 + beam.agentsim.agents.modalBehaviors.highTimeSensitivity.highCongestion.highwayFactor.LevelLE2 = 1.0 + beam.agentsim.agents.modalBehaviors.highTimeSensitivity.highCongestion.nonHighwayFactor.LevelLE2 = 1.0 + beam.agentsim.agents.modalBehaviors.highTimeSensitivity.lowCongestion.highwayFactor.LevelLE2 = 1.0 + beam.agentsim.agents.modalBehaviors.highTimeSensitivity.lowCongestion.nonHighwayFactor.LevelLE2 = 1.0 + beam.agentsim.agents.modalBehaviors.lowTimeSensitivity.highCongestion.highwayFactor.LevelLE2 = 1.0 + beam.agentsim.agents.modalBehaviors.lowTimeSensitivity.highCongestion.nonHighwayFactor.LevelLE2 = 1.0 + beam.agentsim.agents.modalBehaviors.lowTimeSensitivity.lowCongestion.highwayFactor.LevelLE2 = 1.0 + beam.agentsim.agents.modalBehaviors.lowTimeSensitivity.lowCongestion.nonHighwayFactor.LevelLE2 = 1.0 beam.agentsim.agents.modalBehaviors.mulitnomialLogit.params.transfer = -1.4 beam.agentsim.agents.modalBehaviors.mulitnomialLogit.params.car_intercept = 0.0 + beam.agentsim.agents.modalBehaviors.mulitnomialLogit.params.cav_intercept = 0.0 beam.agentsim.agents.modalBehaviors.mulitnomialLogit.params.walk_transit_intercept = 0.0 - beam.agentsim.agents.modalBehaviors.mulitnomialLogit.params.drive_transit_intercept = 2.0 + beam.agentsim.agents.modalBehaviors.mulitnomialLogit.params.drive_transit_intercept = 0.0 beam.agentsim.agents.modalBehaviors.mulitnomialLogit.params.ride_hail_transit_intercept = 0.0 - beam.agentsim.agents.modalBehaviors.mulitnomialLogit.params.ride_hail_intercept = -1.0 - beam.agentsim.agents.modalBehaviors.mulitnomialLogit.params.walk_intercept = -3.0 + beam.agentsim.agents.modalBehaviors.mulitnomialLogit.params.ride_hail_intercept = 0.0 + beam.agentsim.agents.modalBehaviors.mulitnomialLogit.params.ride_hail_pooled_intercept = 0.0 + beam.agentsim.agents.modalBehaviors.mulitnomialLogit.params.walk_intercept = 0.0 beam.agentsim.agents.modalBehaviors.mulitnomialLogit.params.bike_intercept = 0.0 + beam.agentsim.agents.modalBehaviors.mulitnomialLogit.params.bike_transit_intercept = 0.0 beam.agentsim.agents.modalBehaviors.mulitnomialLogit.params.transit_crowding = 0.0 beam.agentsim.agents.modalBehaviors.mulitnomialLogit.params.transit_crowding_percentile = 90 + beam.agentsim.agents.modalBehaviors.mulitnomialLogit.utility_scale_factor = 1.0 beam.agentsim.agents.modalBehaviors.lccm.paramFile = ${beam.inputDirectory}"/lccm-long.csv" #Toll params beam.agentsim.toll.file=${beam.inputDirectory}"/toll-prices.csv" * modeChoiceClass: Selects the choice algorithm to be used by agents to select mode when faced with a choice. Default of ModeChoiceMultinomialLogit is recommended but other algorithms include ModeChoiceMultinomialLogit ModeChoiceTransitIfAvailable ModeChoiceDriveIfAvailable ModeChoiceRideHailIfAvailable ModeChoiceUniformRandom ModeChoiceLCCM. +* maximumNumberOfReplanningAttempts: Replanning happens if a Person cannot have some resource required to continue trip in the chosen mode. If the number of replanning exceeded this value WALK mode is chosen. * defaultValueOfTime: This value of time is used by the ModeChoiceMultinomialLogit choice algorithm unless the value of time is specified in the populationAttributes file. +* minimumValueOfTime: value of time cannot be lower than this value +* modeVotMultiplier: allow to modify value of time for a particular trip mode +* modeVotMultiplier.waiting: not used now +* overrideAutomationLevel: the value to be used to override the vehicle automation level when calculating generalized time +of ride-hail legs +* overrideAutomationForVOTT: enabled overriding of automation level (see overrideAutomationLevel) +* poolingMultiplier: this multiplier is used when calculating generalized time for pooled ride-hail trip for a particular +vehicle automation level +* highTimeSensitivity.highCongestion.highwayFactor.Level5 when a person go by car (not ride-hail) these params allow to set generalized time multiplier for a particular link for different situations: work trip/other trips, high/low traffic, highway or not, vehicle automation level * params.transfer: Constant utility (where 1 util = 1 dollar) of making transfers during a transit trip. * params.car_intercept: Constant utility (where 1 util = 1 dollar) of driving. +* params.cav_intercept: Constant utility (where 1 util = 1 dollar) of using CAV. * params.walk_transit_intercept: Constant utility (where 1 util = 1 dollar) of walking to transit. * params.drive_transit_intercept: Constant utility (where 1 util = 1 dollar) of driving to transit. * params.ride_hail_transit_intercept: Constant utility (where 1 util = 1 dollar) of taking ride hail to/from transit. * params.ride_hail_intercept: Constant utility (where 1 util = 1 dollar) of taking ride hail. +* params.ride_hail_pooled_intercept: Constant utility (where 1 util = 1 dollar) of taking pooled ride hail. * params.walk_intercept: Constant utility (where 1 util = 1 dollar) of walking. * params.bike_intercept: Constant utility (where 1 util = 1 dollar) of biking. +* params.bike_transit_intercept: Constant utility (where 1 util = 1 dollar) of biking to transit. * params.transit_crowding: Multiplier utility of avoiding "crowded" transit vehicle. Should be negative. * params.transit_crowding_percentile: Which percentile to use to get the occupancyLevel (number of passengers / vehicle capacity). The route may have different occupancy levels during the legs/vehicle stops. +* utility_scale_factor: amount by which utilites are scaled before evaluating probabilities. Smaller numbers leads to less determinism * lccm.paramFile: if modeChoiceClass is set to `ModeChoiceLCCM` this must point to a valid file with LCCM parameters. Otherwise, this parameter is ignored. * toll.file: File path to a file with static road tolls. Note, this input will change in future BEAM release where time-varying tolls will possible. @@ -154,6 +221,65 @@ TAZs, Scaling, and Physsim Tuning * physsim.parbprsim.syncInterval: The sync interval in seconds for PARBPRsim. When the sim time reaches this interval in a particular cluster then it waits for the other clusters at that time point. +Routing Configuration +^^^^^^^^^^^^^^^^^^^^^ +:: + +# values: R5, staticGH, quasiDynamicGH, nativeCCH (Linux Only) +beam.routing.carRouter="R5" +beam.routing { + #Base local date in ISO 8061 YYYY-MM-DDTHH:MM:SS+HH:MM + baseDate = "2016-10-17T00:00:00-07:00" + transitOnStreetNetwork = true # PathTraversalEvents for transit vehicles + r5 { + directory = ${beam.inputDirectory}"/r5" + # Departure window in min + departureWindow = "double | 15.0" + numberOfSamples = "int | 1" + osmFile = ${beam.routing.r5.directory}"/beamville.osm.pbf" + osmMapdbFile = ${beam.routing.r5.directory}"/osm.mapdb" + mNetBuilder.fromCRS = "EPSG:4326" # WGS84 + mNetBuilder.toCRS = "EPSG:26910" # UTM10N + travelTimeNoiseFraction = 0.0 + maxDistanceLimitByModeInMeters { + bike = 40000 + } + bikeLaneScaleFactor = 1.0 + bikeLaneLinkIdsFilePath = "" + } + startingIterationForTravelTimesMSA = 0 + overrideNetworkTravelTimesUsingSkims = false + + # Set a lower bound on travel times that can possibly be used to override the network-based + # travel time in the route.This is used to prevent unrealistically fast trips or negative + # duration trips. + minimumPossibleSkimBasedTravelTimeInS= 60 + skimTravelTimesScalingFactor = 0.0 + writeRoutingStatistic = false +} + +Parameters within beam.routing namespace +* carRouter: type of car router. The values are R5, staticGH, quasiDynamicGH, nativeCCH (Linux Only) where staticGH is GraphHopper router (when link travel times don't depend on time of the day), quasiDynamicGH is GraphHopper router (link +travel times depend on time of the day), nativeCCH is router that uses native CCH library. +* baseDate: the date which routes are requested on (transit depends on it) +* transitOnStreetNetwork: if set to true transit PathTraversalEvents includes the route links +* r5.directory: the directory that contains R5 data which includes pbf file, GTFS files. +* r5.departureWindow: the departure window for transit requests +* r5.numberOfSamples: Number of Monte Carlo draws to take for frequency searches when doing routing +* r5.osmMapdbFile: osm map db file that is stored to this location +* r5.mNetBuilder.fromCRS: convert network coordinates from this CRS +* r5.mNetBuilder.toCRS: convert network coordinates to this CRS +* r5.travelTimeNoiseFraction: if it's greater than zero some noise to link travel times will be added +* r5.maxDistanceLimitByModeInMeters: one can limit max distance to be used for a particular mode +* r5.bikeLaneScaleFactor: this parameter is intended to make the links with bike lanes to be more preferable when the + router calculates a route for bikes. The less this scaleFactor the more preferable these links get +* r5.bikeLaneLinkIdsFilePath: the ids of links that have bike lanes +* startingIterationForTravelTimesMSA: ??? +* overrideNetworkTravelTimesUsingSkims: travel time is got from skims +* minimumPossibleSkimBasedTravelTimeInS: minimum skim based travel time +* skimTravelTimesScalingFactor: used to scale skim based travel time +* writeRoutingStatistic: if set to true writes origin-destination pairs that a route wasn't found between + Warm Mode ^^^^^^^^^ :: @@ -181,18 +307,22 @@ Ride hail management # RideHail ################################################################## # Ride Hailing General Params - beam.agentsim.agents.rideHail.numDriversAsFractionOfPopulation=0.1 + beam.agentsim.agents.rideHail.name = "GlobalRHM" + beam.agentsim.agents.rideHail.initialization.initType = "PROCEDURAL" # Other possible values - FILE + beam.agentsim.agents.rideHail.initialization.procedural.vehicleTypePrefix = "RH" + beam.agentsim.agents.rideHail.initialization.procedural.vehicleTypeId = "Car" + beam.agentsim.agents.rideHail.initialization.procedural.fractionOfInitialVehicleFleet = "double | 0.1" + beam.agentsim.agents.rideHail.initialization.procedural.initialLocation.name = "HOME" + beam.agentsim.agents.rideHail.initialization.procedural.initialLocation.home.radiusInMeters = 10000 + beam.agentsim.agents.rideHail.initialization.filePath = "" + beam.agentsim.agents.rideHail.initialization.parking.filePath = "" + beam.agentsim.agents.rideHail.defaultCostPerMile=1.25 beam.agentsim.agents.rideHail.defaultCostPerMinute=0.75 - beam.agentsim.agents.rideHail.vehicleTypeId="BEV" - beam.agentsim.agents.rideHail.refuelThresholdInMeters=5000.0 - beam.agentsim.agents.rideHail.refuelLocationType="AtRequestLocation" - # SurgePricing parameters - beam.agentsim.agents.rideHail.surgePricing.surgeLevelAdaptionStep=0.1 - beam.agentsim.agents.rideHail.surgePricing.minimumSurgeLevel=0.1 - - # priceAdjustmentStrategy(KEEP_PRICE_LEVEL_FIXED_AT_ONE | CONTINUES_DEMAND_SUPPLY_MATCHING) - beam.agentsim.agents.rideHail.surgePricing.priceAdjustmentStrategy="KEEP_PRICE_LEVEL_FIXED_AT_ONE" + beam.agentsim.agents.rideHail.defaultBaseCost = 1.8 + beam.agentsim.agents.rideHail.pooledBaseCost = 1.89 + beam.agentsim.agents.rideHail.pooledCostPerMile = 1.11 + beam.agentsim.agents.rideHail.pooledCostPerMinute = 0.07 beam.agentsim.agents.rideHail.rideHailManager.radiusInMeters=5000 @@ -201,10 +331,34 @@ Ride hail management beam.agentsim.agents.rideHail.initialLocation.home.radiusInMeters=10000 # allocationManager(DEFAULT_MANAGER | REPOSITIONING_LOW_WAITING_TIMES | EV_MANAGER) - beam.agentsim.agents.rideHail.allocationManager.name="EV_MANAGER" - beam.agentsim.agents.rideHail.allocationManager.timeoutInSeconds=300 - beam.agentsim.agents.rideHail.allocationManager.randomRepositioning.repositioningShare=0.2 - + beam.agentsim.agents.rideHail.allocationManager.name = "DEFAULT_MANAGER" + beam.agentsim.agents.rideHail.allocationManager.maxWaitingTimeInSec = 900 + beam.agentsim.agents.rideHail.allocationManager.maxExcessRideTime = 0.5 # up to +50% + beam.agentsim.agents.rideHail.allocationManager.requestBufferTimeoutInSeconds = 0 + # ASYNC_GREEDY_VEHICLE_CENTRIC_MATCHING, ALONSO_MORA_MATCHING_WITH_ASYNC_GREEDY_ASSIGNMENT, ALONSO_MORA_MATCHING_WITH_MIP_ASSIGNMENT + beam.agentsim.agents.rideHail.allocationManager.matchingAlgorithm = "ALONSO_MORA_MATCHING_WITH_ASYNC_GREEDY_ASSIGNMENT" + # ALONSO MORA + beam.agentsim.agents.rideHail.allocationManager.alonsoMora.maxRequestsPerVehicle = 5 + # Reposition + beam.agentsim.agents.rideHail.allocationManager.pooledRideHailIntervalAsMultipleOfSoloRideHail = 1 + + beam.agentsim.agents.rideHail.linkFleetStateAcrossIterations = false + + beam.agentsim.agents.rideHail.repositioningManager.name = "DEFAULT_REPOSITIONING_MANAGER" + beam.agentsim.agents.rideHail.repositioningManager.timeout = 0 + # Larger value increase probability of the ride-hail vehicle to reposition + beam.agentsim.agents.rideHail.repositioningManager.demandFollowingRepositioningManager.sensitivityOfRepositioningToDemand = 1 + beam.agentsim.agents.rideHail.repositioningManager.demandFollowingRepositioningManager.sensitivityOfRepositioningToDemandForCAVs = 1 + beam.agentsim.agents.rideHail.repositioningManager.demandFollowingRepositioningManager.numberOfClustersForDemand = 30 + beam.agentsim.agents.rideHail.repositioningManager.demandFollowingRepositioningManager.fractionOfClosestClustersToConsider = 0.2 + beam.agentsim.agents.rideHail.repositioningManager.demandFollowingRepositioningManager.horizon = 1200 + # inverse Square Distance Repositioning Factor + beam.agentsim.agents.rideHail.repositioningManager.inverseSquareDistanceRepositioningFactor.sensitivityOfRepositioningToDemand = 0.4 + beam.agentsim.agents.rideHail.repositioningManager.inverseSquareDistanceRepositioningFactor.sensitivityOfRepositioningToDistance = 0.9 + beam.agentsim.agents.rideHail.repositioningManager.inverseSquareDistanceRepositioningFactor.predictionHorizon = 3600 + # reposition Low Waiting Times + beam.agentsim.agents.rideHail.allocationManager.repositionLowWaitingTimes.repositionCircleRadiusInMeters = 3000 + beam.agentsim.agents.rideHail.allocationManager.repositionLowWaitingTimes.minimumNumberOfIdlingVehiclesThresholdForRepositioning = 1 beam.agentsim.agents.rideHail.allocationManager.repositionLowWaitingTimes.repositionCircleRadisInMeters=3000.0 beam.agentsim.agents.rideHail.allocationManager.repositionLowWaitingTimes.minimumNumberOfIdlingVehiclesThreshholdForRepositioning=1 beam.agentsim.agents.rideHail.allocationManager.repositionLowWaitingTimes.percentageOfVehiclesToReposition=1.0 @@ -220,17 +374,97 @@ Ride hail management beam.agentsim.agents.rideHail.allocationManager.repositionLowWaitingTimes.demandWeight=4.0 beam.agentsim.agents.rideHail.allocationManager.repositionLowWaitingTimes.produceDebugImages=true - beam.agentsim.agents.rideHail.iterationStats.timeBinSizeInSec=3600 + beam.agentsim.agents.rideHail.cav.valueOfTime = 1.00 + # when range below refuelRequiredThresholdInMeters, EV Ride Hail CAVs will charge + # when range above noRefuelThresholdInMeters, EV Ride Hail CAVs will not charge + # (between these params probability of charging is linear interpolation from 0% to 100%) + beam.agentsim.agents.rideHail.human.refuelRequiredThresholdInMeters = 32180.0 # 20 miles + beam.agentsim.agents.rideHail.human.noRefuelThresholdInMeters = 128720.0 # 80 miles + beam.agentsim.agents.rideHail.cav.refuelRequiredThresholdInMeters = 16090.0 # 10 miles + beam.agentsim.agents.rideHail.cav.noRefuelThresholdInMeters = 96540.0 # 60 miles + beam.agentsim.agents.rideHail.rangeBufferForDispatchInMeters = 10000 # do not dispatch vehicles below this range to ensure enough available to get to charger -* numDriversAsFractionOfPopulation: Defines the # of ride hailing drivers to create, this ration is multiplied by the parameter beam.agentsim.numAgents to determine the actual number of drivers to create. Drivers begin the simulation located at or near the homes of existing agents, uniformly distributed. -* defaultCostPerMile: One component of the 2 part price of ride hail calculation. -* defaultCostPerMinute: One component of the 2 part price of ride hail calculation. -* vehicleTypeId: What vehicle type is used for ride hail vehicles. This is primarily relevant for when allocationManager is `EV_MANAGER`. -* refuelThresholdInMeters: One the fuel level (state of charge for EVs) of the vehicle falls below the level corresponding to this parameter, the `EV_MANAGER` will dispatch the vehicle to refuel. Note, do not make this value greate than 80% of the total vehicle range to avoid complications associated with EV fast charging. -* refuelLocationType: One of `AtRequestLocation` or `AtTAZCenter` which controls whether the vehicle is assumed to charge at the it's present location (`AtRequestLocation`) or whether it will drive to a nearby charging depot (`AtTAZCenter`). -* allocationManager.name: Controls whether fleet management is simple (DEFAULT_MANAGER for no repositioning, no refueling), includes repositioing (REPOSITIONING_LOW_WAITING_TIMES) or includes both repositioning and refueling (EV_MANAGER) -* allocationManager.timeoutInSeconds: How frequently does the manager make fleet repositioning decisions. -* beam.agentsim.agents.rideHail.allocationManager.repositionLowWaitingTimes: All of these parameters control the details of repositioning, more documentation will be posted for these soon. + # priceAdjustmentStrategy(KEEP_PRICE_LEVEL_FIXED_AT_ONE | CONTINUES_DEMAND_SUPPLY_MATCHING) + beam.agentsim.agents.rideHail.surgePricing.priceAdjustmentStrategy="KEEP_PRICE_LEVEL_FIXED_AT_ONE" + # SurgePricing parameters + beam.agentsim.agents.rideHail.surgePricing.surgeLevelAdaptionStep=0.1 + beam.agentsim.agents.rideHail.surgePricing.minimumSurgeLevel=0.1 + beam.agentsim.agents.rideHail.surgePricing.priceAdjustmentStrategy = "KEEP_PRICE_LEVEL_FIXED_AT_ONE" + beam.agentsim.agents.rideHail.surgePricing.numberOfCategories = 6 + + beam.agentsim.agents.rideHail.charging.vehicleChargingManager.defaultVehicleChargingManager.mulitnomialLogit.params.drivingTimeMultiplier = -0.01666667 // one minute of driving is one util + beam.agentsim.agents.rideHail.charging.vehicleChargingManager.defaultVehicleChargingManager.mulitnomialLogit.params.queueingTimeMultiplier = -0.01666667 // one minute of queueing is one util + beam.agentsim.agents.rideHail.charging.vehicleChargingManager.defaultVehicleChargingManager.mulitnomialLogit.params.chargingTimeMultiplier = -0.01666667 // one minute of charging is one util + beam.agentsim.agents.rideHail.charging.vehicleChargingManager.defaultVehicleChargingManager.mulitnomialLogit.params.insufficientRangeMultiplier = -60.0 // indicator variable so straight 60 minute penalty if out of range + + beam.agentsim.agents.rideHail.iterationStats.timeBinSizeInSec = 3600.0 + +* name: RH vehicles prefer parking on parking zones with reservedFor parameter equals to this value +* initialization.initType: type of ridehail fleet initialization +* initialization.procedural.vehicleTypePrefix: the vehicle type prefix that indicates ridehail vehicles +* initialization.procedural.vehicleTypeId: default ridehail vehicle type +* initialization.procedural.fractionOfInitialVehicleFleet: Defines the # of ride hailing agents to create, this ration is multiplied by the parameter total number of household vehicles to determine the actual number of drivers to create. Agents begin the simulation located at or near the homes of existing agents, uniformly distributed. +* initialization.procedural.initialLocation.name: the way to set the initial location for ride-hail vehicles (HOME, RANDOM_ACTIVITY, UNIFORM_RANDOM, ALL_AT_CENTER, ALL_IN_CORNER) +* initialization.procedural.initialLocation.home.radiusInMeters: radius within which the initial location is taken +* initialization.filePath: this file is loaded when initialization.initType is "FILE" +* initialization.parking.filePath: parking zones defined for ridehail fleet; it may be empty. +* defaultCostPerMile: cost per mile for ride hail price calculation for solo riders. +* defaultCostPerMinute: cost per minute for ride hail price calculation for solo riders. +* defaultBaseCost: base RH cost for solo riders +* pooledBaseCost: base RH cost for pooled riders +* pooledCostPerMile: cost per mile for ride hail price calculation for pooled riders. +* pooledCostPerMinute: cost per minute for ride hail price calculation for pooled riders. +* surgePricing.priceAdjustmentStrategy: defines different price adjustment strategies +* surgePricing.surgeLevelAdaptionStep: +* surgePricing.minimumSurgeLevel: +* surgePricing.numberOfCategories: +* radiusInMeters: used during vehicle allocation: considered vehicles that are not further from the request location + than this value +* allocationManager.name: RideHail resource allocation manager: DEFAULT_MANAGER, POOLING, POOLING_ALONSO_MORA +* allocationManager.maxWaitingTimeInSec: max waiting time for a person during RH allocation +* allocationManager.maxExcessRideTime: max excess ride time fraction +* allocationManager.requestBufferTimeoutInSeconds: ride hail requests are buffered within this time before go to allocation manager +* allocationManager.matchingAlgorithm: matching algorithm +* allocationManager.alonsoMora.maxRequestsPerVehicle: the maximum number of requests that can be considered for a single vehicle +* allocationManager.pooledRideHailIntervalAsMultipleOfSoloRideHail: +* linkFleetStateAcrossIterations: if it is set to true then in the next iteration ride-hail fleet state of charge is initialized with the value from the end of previous iteration +* repositioningManager.name: repositioning manager name (DEFAULT_REPOSITIONING_MANAGER, DEMAND_FOLLOWING_REPOSITIONING_MANAGER, INVERSE_SQUARE_DISTANCE_REPOSITIONING_FACTOR, REPOSITIONING_LOW_WAITING_TIMES, THE_SAME_LOCATION_REPOSITIONING_MANAGER, ALWAYS_BE_REPOSITIONING_MANAGER) +* repositioningManager.timeout: time interval of repositioning +* repositioningManager.demandFollowingRepositioningManager.sensitivityOfRepositioningToDemand: should be in [0, 1]; larger value increase probability of the ride-hail vehicle to reposition +* repositioningManager.demandFollowingRepositioningManager.sensitivityOfRepositioningToDemandForCAVs: the same as sensitivityOfRepositioningToDemand but for CAVs +* repositioningManager.demandFollowingRepositioningManager.numberOfClustersForDemand: number of clusters that activity locations is divided to +* repositioningManager.demandFollowingRepositioningManager.fractionOfClosestClustersToConsider: when finding where to reposition this fraction of closest clusters is considered +* repositioningManager.demandFollowingRepositioningManager.horizon: the time bin size +* repositioningManager.inverseSquareDistanceRepositioningFactor.sensitivityOfRepositioningToDemand: larger value increase probability of the ride-hail vehicle to reposition +* repositioningManager.inverseSquareDistanceRepositioningFactor.sensitivityOfRepositioningToDistance: distance is multiplied by this value +* repositioningManager.inverseSquareDistanceRepositioningFactor.predictionHorizon: +* allocationManager.repositionLowWaitingTimes.repositionCircleRadiusInMeters: +* allocationManager.repositionLowWaitingTimes.minimumNumberOfIdlingVehiclesThresholdForRepositioning: +* allocationManager.repositionLowWaitingTimes.repositionCircleRadisInMeters: +* allocationManager.repositionLowWaitingTimes.minimumNumberOfIdlingVehiclesThreshholdForRepositioning: +* allocationManager.repositionLowWaitingTimes.percentageOfVehiclesToReposition: +* allocationManager.repositionLowWaitingTimes.timeWindowSizeInSecForDecidingAboutRepositioning: +* allocationManager.repositionLowWaitingTimes.allowIncreasingRadiusIfDemandInRadiusLow: +* allocationManager.repositionLowWaitingTimes.minDemandPercentageInRadius: +* allocationManager.repositionLowWaitingTimes.repositioningMethod: +* allocationManager.repositionLowWaitingTimes.keepMaxTopNScores: +* allocationManager.repositionLowWaitingTimes.minScoreThresholdForRepositioning: +* allocationManager.repositionLowWaitingTimes.distanceWeight: +* allocationManager.repositionLowWaitingTimes.waitingTimeWeight: +* allocationManager.repositionLowWaitingTimes.demandWeight: +* allocationManager.repositionLowWaitingTimes.produceDebugImages: +* cav.valueOfTime: is used when searching a parking stall for CAVs +* human.refuelRequiredThresholdInMeters: when range below this value, ride-hail vehicle driven by a human will charge +* human.noRefuelThresholdInMeters: when range above noRefuelThresholdInMeters, ride-hail vehicle driven by a human will not charge +* cav.refuelRequiredThresholdInMeters: when range below this value, EV ride-hail CAVs will charge +* cav.noRefuelThresholdInMeters: when range above noRefuelThresholdInMeters, EV ride-hail CAVs will not charge +* rangeBufferForDispatchInMeters: do not dispatch vehicles below this range to ensure enough available to get to charger +* charging.vehicleChargingManager.defaultVehicleChargingManager.mulitnomialLogit.params.drivingTimeMultiplier: one minute of driving is one util +* charging.vehicleChargingManager.defaultVehicleChargingManager.mulitnomialLogit.params.queueingTimeMultiplier: one minute of queueing is one util +* charging.vehicleChargingManager.defaultVehicleChargingManager.mulitnomialLogit.params.chargingTimeMultiplier: one minute of charging is one util +* charging.vehicleChargingManager.defaultVehicleChargingManager.mulitnomialLogit.params.insufficientRangeMultiplier: indicator variable so straight 60 minute penalty if out of range + +* iterationStats.timeBinSizeInSec: time bin size of ride-hail statistic Secondary activities generation ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -296,4 +530,50 @@ Output * beam.output.writePlansAndStopSimulation - if set to true will write plans into 'generatedPlans.csv.gz' and stop simulation with exception at the beginning of agentSim iteration. - The functionality was created to generate full population plans with secondary activities for full unscaled input. \ No newline at end of file + The functionality was created to generate full population plans with secondary activities for full unscaled input. + +Defining what data BEAM writes out +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +There's the list of parameters responsible for writing out data produced by BEAM. + +:: + + beam.router.skim.writeSkimsInterval = 0 + beam.router.skim.writeAggregatedSkimsInterval = 0 + beam.router.skim.origin-destination-skimmer.writeAllModeSkimsForPeakNonPeakPeriodsInterval = 0 + beam.router.skim.origin-destination-skimmer.writeFullSkimsInterval = 0 + beam.debug.writeModeChoiceAlternatives = false + beam.debug.writeRealizedModeChoiceFile = false + beam.outputs.writeGraphs = true + beam.outputs.writePlansInterval = 0 + beam.outputs.writeEventsInterval = 1 + beam.outputs.writeAnalysis = true + beam.outputs.writeR5RoutesInterval = 0 + beam.physsim.writeEventsInterval = 0 + beam.physsim.events.fileOutputFormats = "csv" # valid options: xml(.gz) , csv(.gz), none - DEFAULT: csv.gz + beam.physsim.events.eventsToWrite = "ActivityEndEvent,ActivityStartEvent,LinkEnterEvent,LinkLeaveEvent,PersonArrivalEvent,PersonDepartureEvent,VehicleEntersTrafficEvent,VehicleLeavesTrafficEvent" + beam.physsim.writePlansInterval = 0 + beam.physsim.writeRouteHistoryInterval = 10 + beam.physsim.linkStatsWriteInterval = 0 + beam.outputs.generalizedLinkStatsInterval = 0 + +All integer values that end with 'Interval' mean writing data files at iteration which number % value = 0. In case value = 0 +writing is disabled. + +* beam.router.skim.writeSkimsInterval: enable writing all skim data for a particular iteration to corresponding files +* beam.router.skim.writeAggregatedSkimsInterval: enable writing all aggregated skim data (for all iterations) to corresponding files +* beam.router.skim.origin-destination-skimmer.writeAllModeSkimsForPeakNonPeakPeriodsInterval: enable writing ODSkims for peak and non-peak time periods to #.skimsODExcerpt.csv.gz +* beam.router.skim.origin-destination-skimmer.writeFullSkimsInterval: enable writing ODSkims for all TAZes presented in the scenario to #.skimsODFull.csv.gz +* beam.outputs.writeGraphs: enable writing activity locations to #.activityLocations.png +* beam.outputs.writePlansInterval: enable writing plans of persons at the iteration to #.plans.csv.gz +* beam.outputs.writeEventsInterval: enable writing AgentSim events to #.events.csv.gz +* beam.outputs.writeAnalysis: enable analysis with python script analyze_events.py and writing different data files +* beam.outputs.writeR5RoutesInterval: enable writing routing requests/responses to files #.routingRequest.parquet, #.routingResponse.parquet, #.embodyWithCurrentTravelTime.parquet +* beam.physsim.writeEventsInterval: enable writing physsim events to #.physSimEvents.csv.gz +* beam.physsim.events.fileOutputFormats: file format for physsim event file; valid options: xml(.gz) , csv(.gz), none - DEFAULT: csv.gz +* beam.physsim.events.eventsToWrite: types of physsim events to write +* beam.physsim.writePlansInterval: enable writing of physsim plans to #.physsimPlans.xml.gz +* beam.physsim.writeRouteHistoryInterval: enable writing route history to #.routeHistory.csv.gz. It contains timeBin,originLinkId,destLinkId,route (link ids) +* beam.physsim.linkStatsWriteInterval: enable writing link statistic to #.linkstats_unmodified.csv.gz" +* beam.outputs.generalizedLinkStatsInterval: enable writing generalized link statistic (with generalized time and cost) to #.generalizedLinkStats.csv.gz \ No newline at end of file diff --git a/src/main/resources/beam-template.conf b/src/main/resources/beam-template.conf index 64c1b3039b7..c7acb17f322 100755 --- a/src/main/resources/beam-template.conf +++ b/src/main/resources/beam-template.conf @@ -196,8 +196,6 @@ beam.agentsim.agents.rideHail.pooledCostPerMinute = 0.07 beam.agentsim.agents.rideHail.initialization.procedural.vehicleTypeId = "Car" beam.agentsim.agents.rideHail.initialization.procedural.vehicleTypePrefix = "RH" beam.agentsim.agents.rideHail.initialization.procedural.fractionOfInitialVehicleFleet = "double | 0.1" -beam.agentsim.agents.rideHail.refuelThresholdInMeters = "double | 5000.0" -beam.agentsim.agents.rideHail.refuelLocationType = "AtTAZCenter" beam.agentsim.agents.rideHail.rideHailManager.radiusInMeters = "double | 5000" beam.agentsim.agents.rideHail.allocationManager.maxWaitingTimeInSec = "int | 900" beam.agentsim.agents.rideHail.allocationManager.maxExcessRideTime = "double | 0.5" # up to +50% @@ -240,10 +238,6 @@ beam.agentsim.agents.rideHail.allocationManager.repositionLowWaitingTimes.waitin beam.agentsim.agents.rideHail.allocationManager.repositionLowWaitingTimes.demandWeight = "double | 4.0" beam.agentsim.agents.rideHail.allocationManager.repositionLowWaitingTimes.produceDebugImages = true -beam.agentsim.agents.rideHail.pooledToRegularRideCostRatio = 0.6 - -# human value of time taken from # https://theicct.org/sites/default/files/publications/Electric_shared_mobility_20190114.pdf -beam.agentsim.agents.rideHail.human.valueOfTime = 22.90 beam.agentsim.agents.rideHail.cav.valueOfTime = 1.00 # when range below refuelRequiredThresholdInMeters, EV Ride Hail CAVs will charge # when range above noRefuelThresholdInMeters, EV Ride Hail CAVs will not charge @@ -254,15 +248,10 @@ beam.agentsim.agents.rideHail.cav.refuelRequiredThresholdInMeters = 16090.0 # 10 beam.agentsim.agents.rideHail.cav.noRefuelThresholdInMeters = 96540.0 # 60 miles beam.agentsim.agents.rideHail.rangeBufferForDispatchInMeters = 10000 # do not dispatch vehicles below this range to ensure enough available to get to charger -# VEHICLE CHARGING MANAGER NAME OPTIONS: -# DefaultVehicleChargingManager, NoChargingManager -beam.agentsim.agents.rideHail.charging.vehicleChargingManager.name = "DefaultVehicleChargingManager" -beam.agentsim.agents.rideHail.charging.vehicleChargingManager.defaultVehicleChargingManager.noChargingThresholdExpirationTimeInS = "int | 0" beam.agentsim.agents.rideHail.charging.vehicleChargingManager.defaultVehicleChargingManager.mulitnomialLogit.params.drivingTimeMultiplier = "double | -0.01666667" // one minute of driving is one util beam.agentsim.agents.rideHail.charging.vehicleChargingManager.defaultVehicleChargingManager.mulitnomialLogit.params.queueingTimeMultiplier = "double | -0.01666667" // one minute of queueing is one util beam.agentsim.agents.rideHail.charging.vehicleChargingManager.defaultVehicleChargingManager.mulitnomialLogit.params.chargingTimeMultiplier = "double | -0.01666667" // one minute of charging is one util beam.agentsim.agents.rideHail.charging.vehicleChargingManager.defaultVehicleChargingManager.mulitnomialLogit.params.insufficientRangeMultiplier = "double | -60.0" // indicator variable so straight 60 minute penalty if out of range -beam.agentsim.agents.rideHail.charging.vehicleChargingManager.defaultVehicleChargingManager.fractionAvailableThresholdToFavorFasterCharging = "double | 1.01" // by default, always prioritize faster charging beam.agentsim.agents.freight { enabled = false @@ -824,13 +813,11 @@ beam.outputs.defaultWriteInterval = 1 beam.outputs.writePlansInterval = "int | 0" beam.outputs.writeEventsInterval = "int | 1" beam.outputs.writeAnalysis = "boolean | true" -beam.outputs.writeLinkTraversalInterval = "int | 0" beam.outputs.writeR5RoutesInterval = "int | 0" beam.physsim.writeEventsInterval = "int | 0" beam.physsim.writePlansInterval = "int | 0" beam.physsim.writeRouteHistoryInterval = "int | 10" beam.physsim.linkStatsWriteInterval = "int | 0" -beam.physsim.writeMATSimNetwork = "boolean | true" beam.outputs.generalizedLinkStatsInterval = 0 # this will write out plans and throw and exception at the beginning of simulation @@ -896,7 +883,6 @@ beam.routing { # Departure window in min departureWindow = "double | 15.0" numberOfSamples = "int | 1" - osmFile = ${beam.routing.r5.directory}"/beamville.osm.pbf" osmMapdbFile = ${beam.routing.r5.directory}"/osm.mapdb" mNetBuilder.fromCRS = "EPSG:4326" # WGS84 mNetBuilder.toCRS = "EPSG:26910" # UTM10N diff --git a/src/main/scala/beam/agentsim/agents/PersonAgent.scala b/src/main/scala/beam/agentsim/agents/PersonAgent.scala index 8027dcd10f3..3ecf9e71ae0 100755 --- a/src/main/scala/beam/agentsim/agents/PersonAgent.scala +++ b/src/main/scala/beam/agentsim/agents/PersonAgent.scala @@ -666,7 +666,11 @@ class PersonAgent( ) eventsManager.processEvent(teleportationEvent) - goto(ProcessingNextLegOrStartActivity) using data.copy(hasDeparted = true) + goto(ProcessingNextLegOrStartActivity) using data.copy( + hasDeparted = true, + currentVehicle = Vector.empty[Id[BeamVehicle]], + currentTourPersonalVehicle = None + ) } diff --git a/src/main/scala/beam/agentsim/agents/modalbehaviors/ChoosesMode.scala b/src/main/scala/beam/agentsim/agents/modalbehaviors/ChoosesMode.scala index ef9fa49a4ff..c0929796c0b 100755 --- a/src/main/scala/beam/agentsim/agents/modalbehaviors/ChoosesMode.scala +++ b/src/main/scala/beam/agentsim/agents/modalbehaviors/ChoosesMode.scala @@ -130,85 +130,56 @@ trait ChoosesMode { def bodyVehiclePersonId: PersonIdWithActorRef = PersonIdWithActorRef(id, self) onTransition { case _ -> ChoosingMode => + val choosesModeData: ChoosesModeData = nextStateData.asInstanceOf[ChoosesModeData] + val availableModes: Seq[BeamMode] = availableModesForPerson(matsimPlan.getPerson, choosesModeData.excludeModes) + val nextAct = nextActivity(choosesModeData.personData).get + val correctedCurrentTripMode = correctCurrentTripModeAccordingToRules( + choosesModeData.personData.currentTripMode, + choosesModeData.personData, + nextAct, + availableModes + ) nextStateData match { // If I am already on a tour in a vehicle, only that vehicle is available to me case data: ChoosesModeData - if data.personData.currentTourPersonalVehicle.isDefined && ( - data.personData.currentTourMode.exists(mode => mode == CAR || mode == BIKE) - || data.personData.currentTourMode.exists(mode => mode == DRIVE_TRANSIT || mode == BIKE_TRANSIT) - && isLastTripWithinTour(data.personData, nextActivity(data.personData).get) - ) => + if data.personData.currentTourPersonalVehicle.isDefined && + ( + data.personData.currentTourMode.exists(mode => mode == CAR || mode == BIKE) || + data.personData.currentTourMode.exists(mode => mode == DRIVE_TRANSIT || mode == BIKE_TRANSIT) + && isLastTripWithinTour(data.personData, nextAct) + ) => self ! MobilityStatusResponse( Vector(beamVehicles(data.personData.currentTourPersonalVehicle.get)), getCurrentTriggerIdOrGenerate ) // Create teleportation vehicle if we are told to use teleportation - case data: ChoosesModeData if data.personData.currentTripMode.exists(_.isHovTeleportation) => + case data: ChoosesModeData if correctedCurrentTripMode.exists(_.isHovTeleportation) => val teleportationVehicle = createSharedTeleportationVehicle(data.currentLocation) val vehicles = Vector(ActualVehicle(teleportationVehicle)) self ! MobilityStatusResponse(vehicles, getCurrentTriggerIdOrGenerate) // Only need to get available street vehicles if our mode requires such a vehicle - case ChoosesModeData( - BasePersonData( - currentActivityIndex, - _, - _, - _, - plansModeOption @ (None | Some(CAR | BIKE | DRIVE_TRANSIT | BIKE_TRANSIT)), - _, - _, - _, - _, - _, - _, - _, - _, - _, - _ - ), - currentLocation, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _ - ) => + case data: ChoosesModeData if correctedCurrentTripMode.forall(Modes.isPersonalVehicleMode) => implicit val executionContext: ExecutionContext = context.system.dispatcher - plansModeOption match { + correctedCurrentTripMode match { case Some(CAR | DRIVE_TRANSIT) => requestAvailableVehicles( vehicleFleets, - currentLocation, - _experiencedBeamPlan.activities(currentActivityIndex), + data.currentLocation, + currentActivity(data.personData), Some(VehicleCategory.Car) ) pipeTo self case Some(BIKE | BIKE_TRANSIT) => requestAvailableVehicles( vehicleFleets, - currentLocation, - _experiencedBeamPlan.activities(currentActivityIndex), + data.currentLocation, + currentActivity(data.personData), Some(VehicleCategory.Bike) ) pipeTo self case _ => requestAvailableVehicles( vehicleFleets, - currentLocation, - _experiencedBeamPlan.activities(currentActivityIndex) + data.currentLocation, + currentActivity(data.personData) ) pipeTo self } @@ -258,15 +229,19 @@ trait ChoosesMode { val personData = choosesModeData.personData val nextAct = nextActivity(personData).get // Make sure the current mode is allowable - val correctedCurrentTripMode = correctCurrentTripModeAccordingToRules(personData, nextAct, availableModes) + val correctedCurrentTripMode = + correctCurrentTripModeAccordingToRules(personData.currentTripMode, personData, nextAct, availableModes) val bodyStreetVehicle = createBodyStreetVehicle(currentPersonLocation) val departTime = _currentTick.get var availablePersonalStreetVehicles = correctedCurrentTripMode match { - case None | Some(CAR | BIKE | HOV2_TELEPORTATION | HOV3_TELEPORTATION) => - // In these cases, a personal vehicle will be involved + case None | Some(CAR | BIKE) => + // In these cases, a personal vehicle will be involved, but filter out teleportation vehicles + newlyAvailableBeamVehicles.filterNot(v => BeamVehicle.isSharedTeleportationVehicle(v.id)) + case Some(HOV2_TELEPORTATION | HOV3_TELEPORTATION) => + // In these cases, also include teleportation vehicles newlyAvailableBeamVehicles case Some(DRIVE_TRANSIT | BIKE_TRANSIT) => if (isFirstOrLastTripWithinTour(personData, nextAct)) { @@ -722,13 +697,14 @@ trait ChoosesMode { } using completeChoiceIfReady) private def correctCurrentTripModeAccordingToRules( + currentTripMode: Option[BeamMode], personData: BasePersonData, nextAct: Activity, availableModes: Seq[BeamMode] ): Option[BeamMode] = { val replanningIsAvailable = personData.numberOfReplanningAttempts < beamServices.beamConfig.beam.agentsim.agents.modalBehaviors.maximumNumberOfReplanningAttempts - (personData.currentTripMode, personData.currentTourMode) match { + (currentTripMode, personData.currentTourMode) match { case (_, Some(CAR | BIKE)) if personData.currentTourPersonalVehicle.isDefined => personData.currentTourMode case (_, Some(DRIVE_TRANSIT | BIKE_TRANSIT)) if personData.currentTourPersonalVehicle.isDefined && isLastTripWithinTour(personData, nextAct) => @@ -736,6 +712,9 @@ trait ChoosesMode { case (Some(mode @ (HOV2_TELEPORTATION | HOV3_TELEPORTATION)), _) if availableModes.contains(CAR) && replanningIsAvailable => Some(mode) + case (Some(CAR_HOV2 | CAR_HOV3), Some(tourMode @ (HOV2_TELEPORTATION | HOV3_TELEPORTATION))) + if availableModes.contains(CAR) && replanningIsAvailable => + Some(tourMode) case (Some(mode), _) if availableModes.contains(mode) && replanningIsAvailable => Some(mode) case (Some(mode), _) if availableModes.contains(mode) => Some(WALK) case (None, _) if !replanningIsAvailable => Some(WALK) @@ -1033,7 +1012,7 @@ trait ChoosesMode { ): Seq[EmbodiedBeamTrip] = { itineraries.map { itin => itin.tripClassifier match { - case CAR | DRIVE_TRANSIT | BIKE_TRANSIT | BIKE => + case mode if Modes.isPersonalVehicleMode(mode) => // find parking legs (the subsequent leg of the same vehicle) val parkingLegs = itin.legs.zip(itin.legs.tail).collect { case (leg1, leg2) if leg1.beamVehicleId == leg2.beamVehicleId && legVehicleHasParkingBehavior(leg2) => leg2 @@ -1260,7 +1239,7 @@ trait ChoosesMode { } case Some(_) => val correctedTripMode = - correctCurrentTripModeAccordingToRules(personData, nextAct, availableModesForTrips) + correctCurrentTripModeAccordingToRules(None, personData, nextAct, availableModesForTrips) if (correctedTripMode != personData.currentTripMode) { //give another chance to make a choice without predefined mode gotoChoosingModeWithoutPredefinedMode(choosesModeData) @@ -1458,6 +1437,7 @@ trait ChoosesMode { goto(Teleporting) using data.personData.copy( currentTrip = Some(chosenTrip), + currentTourMode = data.personData.currentTripMode, restOfCurrentTrip = List() ) diff --git a/src/main/scala/beam/agentsim/agents/modalbehaviors/DrivesVehicle.scala b/src/main/scala/beam/agentsim/agents/modalbehaviors/DrivesVehicle.scala index da9c4b84921..dc19f806e0b 100755 --- a/src/main/scala/beam/agentsim/agents/modalbehaviors/DrivesVehicle.scala +++ b/src/main/scala/beam/agentsim/agents/modalbehaviors/DrivesVehicle.scala @@ -3,7 +3,6 @@ package beam.agentsim.agents.modalbehaviors import akka.actor.FSM.Failure import akka.actor.{ActorRef, Stash} import beam.agentsim.Resource.{NotifyVehicleIdle, ReleaseParkingStall} -import beam.agentsim.agents.{BeamAgent, PersonAgent} import beam.agentsim.agents.PersonAgent._ import beam.agentsim.agents.modalbehaviors.DrivesVehicle._ import beam.agentsim.agents.parking.ChoosesParking.{handleUseParkingSpot, ConnectingToChargingPoint} @@ -12,6 +11,7 @@ import beam.agentsim.agents.vehicles.AccessErrorCodes.VehicleFullError import beam.agentsim.agents.vehicles.BeamVehicle.{BeamVehicleState, FuelConsumed} import beam.agentsim.agents.vehicles.VehicleProtocol._ import beam.agentsim.agents.vehicles._ +import beam.agentsim.agents.{BeamAgent, PersonAgent} import beam.agentsim.events.RefuelSessionEvent.NotApplicable import beam.agentsim.events._ import beam.agentsim.infrastructure.ChargingNetworkManager._ @@ -22,7 +22,7 @@ import beam.agentsim.scheduler.Trigger.TriggerWithId import beam.agentsim.scheduler.{HasTriggerId, Trigger} import beam.router.Modes.BeamMode import beam.router.Modes.BeamMode.{HOV2_TELEPORTATION, HOV3_TELEPORTATION, WALK} -import beam.router.model.{BeamLeg, BeamPath, EmbodiedBeamLeg} +import beam.router.model.{BeamLeg, BeamPath} import beam.router.osm.TollCalculator import beam.router.skim.event.TransitCrowdingSkimmerEvent import beam.sim.common.GeoUtils @@ -222,7 +222,7 @@ trait DrivesVehicle[T <: DrivingData] extends BeamAgent[T] with Stash with Expon case Event( TriggerWithId(EndLegTrigger(tick), triggerId), LiterallyDrivingData(data: BasePersonData, _, _) - ) if data.currentTripMode.contains(HOV2_TELEPORTATION) || data.currentTourMode.contains(HOV3_TELEPORTATION) => + ) if data.currentTripMode.contains(HOV2_TELEPORTATION) || data.currentTripMode.contains(HOV3_TELEPORTATION) => updateLatestObservedTick(tick) val dataForNextLegOrActivity: BasePersonData = data.copy( @@ -322,7 +322,14 @@ trait DrivesVehicle[T <: DrivingData] extends BeamAgent[T] with Stash with Expon val tollOnCurrentLeg = toll(currentLeg) tollsAccumulated += tollOnCurrentLeg - val riders = data.passengerSchedule.schedule(currentLeg).riders.toIndexedSeq.map(_.personId) + + val riders = { + currentLeg.mode match { + case BeamMode.BIKE | BeamMode.WALK => immutable.IndexedSeq(id.asInstanceOf[Id[Person]]) + case _ => data.passengerSchedule.schedule(currentLeg).riders.toIndexedSeq.map(_.personId) + } + } + val numberOfPassengers: Int = calculateNumberOfPassengersBasedOnCurrentTourMode(data, currentLeg, riders) val pte = PathTraversalEvent( tick, diff --git a/src/main/scala/beam/router/Modes.scala b/src/main/scala/beam/router/Modes.scala index c602f6e4f08..c610f65a285 100755 --- a/src/main/scala/beam/router/Modes.scala +++ b/src/main/scala/beam/router/Modes.scala @@ -125,6 +125,8 @@ object Modes { val chainBasedModes = Seq(CAR, BIKE) + val personalVehicleModes = Seq(CAR, BIKE, DRIVE_TRANSIT, BIKE_TRANSIT) + val transitModes = Seq(BUS, FUNICULAR, GONDOLA, CABLE_CAR, FERRY, TRAM, TRANSIT, RAIL, SUBWAY) @@ -162,6 +164,8 @@ object Modes { def isChainBasedMode(beamMode: BeamMode): Boolean = BeamMode.chainBasedModes.contains(beamMode) + def isPersonalVehicleMode(beamMode: BeamMode): Boolean = BeamMode.personalVehicleModes.contains(beamMode) + implicit def beamMode2R5Mode(beamMode: BeamMode): Either[LegMode, TransitModes] = beamMode.r5Mode.get diff --git a/src/main/scala/beam/sim/RideHailFleetInitializer.scala b/src/main/scala/beam/sim/RideHailFleetInitializer.scala index 298f33fafc2..3e3a1bea283 100644 --- a/src/main/scala/beam/sim/RideHailFleetInitializer.scala +++ b/src/main/scala/beam/sim/RideHailFleetInitializer.scala @@ -610,14 +610,6 @@ class ProceduralRideHailFleetInitializer( realDistribution ) .head - if ( - beamServices.beamConfig.beam.agentsim.agents.rideHail.refuelThresholdInMeters >= - (vehicleType.primaryFuelCapacityInJoule / vehicleType.primaryFuelConsumptionInJoulePerMeter) * 0.8 - ) { - logger.error( - "Ride Hail refuel threshold is higher than state of energy of a vehicle fueled by a DC fast charger. This will cause an infinite loop" - ) - } val rideInitialLocation: Location = getRideInitLocation(person, activityQuadTreeBounds) val meanSoc = beamServices.beamConfig.beam.agentsim.agents.vehicles.meanRidehailVehicleStartingSOC diff --git a/src/main/scala/beam/sim/config/BeamConfig.scala b/src/main/scala/beam/sim/config/BeamConfig.scala index b858a80cc8e..57f17ef5f07 100644 --- a/src/main/scala/beam/sim/config/BeamConfig.scala +++ b/src/main/scala/beam/sim/config/BeamConfig.scala @@ -889,10 +889,7 @@ object BeamConfig { pooledBaseCost: scala.Double, pooledCostPerMile: scala.Double, pooledCostPerMinute: scala.Double, - pooledToRegularRideCostRatio: scala.Double, rangeBufferForDispatchInMeters: scala.Int, - refuelLocationType: java.lang.String, - refuelThresholdInMeters: scala.Double, repositioningManager: BeamConfig.Beam.Agentsim.Agents.RideHail.RepositioningManager, rideHailManager: BeamConfig.Beam.Agentsim.Agents.RideHail.RideHailManager, surgePricing: BeamConfig.Beam.Agentsim.Agents.RideHail.SurgePricing @@ -1043,16 +1040,13 @@ object BeamConfig { object Charging { case class VehicleChargingManager( - defaultVehicleChargingManager: BeamConfig.Beam.Agentsim.Agents.RideHail.Charging.VehicleChargingManager.DefaultVehicleChargingManager, - name: java.lang.String + defaultVehicleChargingManager: BeamConfig.Beam.Agentsim.Agents.RideHail.Charging.VehicleChargingManager.DefaultVehicleChargingManager ) object VehicleChargingManager { case class DefaultVehicleChargingManager( - fractionAvailableThresholdToFavorFasterCharging: scala.Double, - mulitnomialLogit: BeamConfig.Beam.Agentsim.Agents.RideHail.Charging.VehicleChargingManager.DefaultVehicleChargingManager.MulitnomialLogit, - noChargingThresholdExpirationTimeInS: scala.Int + mulitnomialLogit: BeamConfig.Beam.Agentsim.Agents.RideHail.Charging.VehicleChargingManager.DefaultVehicleChargingManager.MulitnomialLogit ) object DefaultVehicleChargingManager { @@ -1114,20 +1108,12 @@ object BeamConfig { ): BeamConfig.Beam.Agentsim.Agents.RideHail.Charging.VehicleChargingManager.DefaultVehicleChargingManager = { BeamConfig.Beam.Agentsim.Agents.RideHail.Charging.VehicleChargingManager .DefaultVehicleChargingManager( - fractionAvailableThresholdToFavorFasterCharging = - if (c.hasPathOrNull("fractionAvailableThresholdToFavorFasterCharging")) - c.getDouble("fractionAvailableThresholdToFavorFasterCharging") - else 1.01, mulitnomialLogit = BeamConfig.Beam.Agentsim.Agents.RideHail.Charging.VehicleChargingManager.DefaultVehicleChargingManager .MulitnomialLogit( if (c.hasPathOrNull("mulitnomialLogit")) c.getConfig("mulitnomialLogit") else com.typesafe.config.ConfigFactory.parseString("mulitnomialLogit{}") - ), - noChargingThresholdExpirationTimeInS = - if (c.hasPathOrNull("noChargingThresholdExpirationTimeInS")) - c.getInt("noChargingThresholdExpirationTimeInS") - else 0 + ) ) } } @@ -1142,8 +1128,7 @@ object BeamConfig { if (c.hasPathOrNull("defaultVehicleChargingManager")) c.getConfig("defaultVehicleChargingManager") else com.typesafe.config.ConfigFactory.parseString("defaultVehicleChargingManager{}") - ), - name = if (c.hasPathOrNull("name")) c.getString("name") else "DefaultVehicleChargingManager" + ) ) } } @@ -1160,8 +1145,7 @@ object BeamConfig { case class Human( noRefuelThresholdInMeters: scala.Int, - refuelRequiredThresholdInMeters: scala.Int, - valueOfTime: scala.Double + refuelRequiredThresholdInMeters: scala.Int ) object Human { @@ -1172,8 +1156,7 @@ object BeamConfig { if (c.hasPathOrNull("noRefuelThresholdInMeters")) c.getInt("noRefuelThresholdInMeters") else 128720, refuelRequiredThresholdInMeters = if (c.hasPathOrNull("refuelRequiredThresholdInMeters")) c.getInt("refuelRequiredThresholdInMeters") - else 32180, - valueOfTime = if (c.hasPathOrNull("valueOfTime")) c.getDouble("valueOfTime") else 22.9 + else 32180 ) } } @@ -1453,16 +1436,9 @@ object BeamConfig { pooledCostPerMile = if (c.hasPathOrNull("pooledCostPerMile")) c.getDouble("pooledCostPerMile") else 1.11, pooledCostPerMinute = if (c.hasPathOrNull("pooledCostPerMinute")) c.getDouble("pooledCostPerMinute") else 0.07, - pooledToRegularRideCostRatio = - if (c.hasPathOrNull("pooledToRegularRideCostRatio")) c.getDouble("pooledToRegularRideCostRatio") - else 0.6, rangeBufferForDispatchInMeters = if (c.hasPathOrNull("rangeBufferForDispatchInMeters")) c.getInt("rangeBufferForDispatchInMeters") else 10000, - refuelLocationType = - if (c.hasPathOrNull("refuelLocationType")) c.getString("refuelLocationType") else "AtTAZCenter", - refuelThresholdInMeters = - if (c.hasPathOrNull("refuelThresholdInMeters")) c.getDouble("refuelThresholdInMeters") else 5000.0, repositioningManager = BeamConfig.Beam.Agentsim.Agents.RideHail.RepositioningManager( if (c.hasPathOrNull("repositioningManager")) c.getConfig("repositioningManager") else com.typesafe.config.ConfigFactory.parseString("repositioningManager{}") @@ -2810,7 +2786,6 @@ object BeamConfig { writeAnalysis: scala.Boolean, writeEventsInterval: scala.Int, writeGraphs: scala.Boolean, - writeLinkTraversalInterval: scala.Int, writePlansInterval: scala.Int, writeR5RoutesInterval: scala.Int ) @@ -2914,8 +2889,6 @@ object BeamConfig { writeAnalysis = !c.hasPathOrNull("writeAnalysis") || c.getBoolean("writeAnalysis"), writeEventsInterval = if (c.hasPathOrNull("writeEventsInterval")) c.getInt("writeEventsInterval") else 1, writeGraphs = !c.hasPathOrNull("writeGraphs") || c.getBoolean("writeGraphs"), - writeLinkTraversalInterval = - if (c.hasPathOrNull("writeLinkTraversalInterval")) c.getInt("writeLinkTraversalInterval") else 0, writePlansInterval = if (c.hasPathOrNull("writePlansInterval")) c.getInt("writePlansInterval") else 0, writeR5RoutesInterval = if (c.hasPathOrNull("writeR5RoutesInterval")) c.getInt("writeR5RoutesInterval") else 0 ) @@ -2949,7 +2922,6 @@ object BeamConfig { speedScalingFactor: scala.Double, storageCapacityFactor: scala.Double, writeEventsInterval: scala.Int, - writeMATSimNetwork: scala.Boolean, writePlansInterval: scala.Int, writeRouteHistoryInterval: scala.Int ) @@ -3825,7 +3797,6 @@ object BeamConfig { storageCapacityFactor = if (c.hasPathOrNull("storageCapacityFactor")) c.getDouble("storageCapacityFactor") else 1.0, writeEventsInterval = if (c.hasPathOrNull("writeEventsInterval")) c.getInt("writeEventsInterval") else 0, - writeMATSimNetwork = !c.hasPathOrNull("writeMATSimNetwork") || c.getBoolean("writeMATSimNetwork"), writePlansInterval = if (c.hasPathOrNull("writePlansInterval")) c.getInt("writePlansInterval") else 0, writeRouteHistoryInterval = if (c.hasPathOrNull("writeRouteHistoryInterval")) c.getInt("writeRouteHistoryInterval") else 10 @@ -4079,7 +4050,6 @@ object BeamConfig { mNetBuilder: BeamConfig.Beam.Routing.R5.MNetBuilder, maxDistanceLimitByModeInMeters: BeamConfig.Beam.Routing.R5.MaxDistanceLimitByModeInMeters, numberOfSamples: scala.Int, - osmFile: java.lang.String, osmMapdbFile: java.lang.String, travelTimeNoiseFraction: scala.Double ) @@ -4133,8 +4103,6 @@ object BeamConfig { else com.typesafe.config.ConfigFactory.parseString("maxDistanceLimitByModeInMeters{}") ), numberOfSamples = if (c.hasPathOrNull("numberOfSamples")) c.getInt("numberOfSamples") else 1, - osmFile = - if (c.hasPathOrNull("osmFile")) c.getString("osmFile") else "/test/input/beamville/r5/beamville.osm.pbf", osmMapdbFile = if (c.hasPathOrNull("osmMapdbFile")) c.getString("osmMapdbFile") else "/test/input/beamville/r5/osm.mapdb", diff --git a/src/test/scala/beam/integration/SingleModeSpec.scala b/src/test/scala/beam/integration/SingleModeSpec.scala index f29744f7c47..0764c304fbe 100755 --- a/src/test/scala/beam/integration/SingleModeSpec.scala +++ b/src/test/scala/beam/integration/SingleModeSpec.scala @@ -11,7 +11,7 @@ import beam.router.RouteHistory import beam.sflight.RouterForTest import beam.sim.common.GeoUtilsImpl import beam.sim.{BeamHelper, BeamMobsim, RideHailFleetInitializerProvider} -import beam.utils.SimRunnerForTest +import beam.utils.{MathUtils, SimRunnerForTest} import beam.utils.TestConfigUtils.testConfig import com.typesafe.config.ConfigFactory import org.matsim.api.core.v01.events.{ActivityEndEvent, Event, PersonDepartureEvent, PersonEntersVehicleEvent} @@ -269,8 +269,10 @@ class SingleModeSpec val personDepartureEvents = events.collect { case event: PersonDepartureEvent => event } personDepartureEvents should not be empty val regularPersonEvents = filterOutProfessionalDriversAndCavs(personDepartureEvents) - val (drive, others) = regularPersonEvents.map(_.getLegMode).partition(_ == "car") - others.size should be < (0.02 * drive.size).toInt + val othersCount = regularPersonEvents.count(_.getLegMode != "car") + withClue("Majority of agents should use cars. Other modes take place when no car available.") { + othersCount should be < MathUtils.doubleToInt(0.02 * regularPersonEvents.size) + } } }