Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/do/#3441-current-trip-tour-mode'…
Browse files Browse the repository at this point in the history
… into Xuan/sfbay-fixing-walking
  • Loading branch information
Xuan-1998 committed Mar 28, 2022
2 parents c4437b5 + de1684a commit ef55850
Show file tree
Hide file tree
Showing 9 changed files with 378 additions and 155 deletions.
336 changes: 308 additions & 28 deletions docs/inputs.rst

Large diffs are not rendered by default.

14 changes: 0 additions & 14 deletions src/main/resources/beam-template.conf
Original file line number Diff line number Diff line change
Expand Up @@ -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%
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
6 changes: 5 additions & 1 deletion src/main/scala/beam/agentsim/agents/PersonAgent.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
)

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -722,20 +697,24 @@ 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) =>
personData.currentTourMode
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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -1458,6 +1437,7 @@ trait ChoosesMode {

goto(Teleporting) using data.personData.copy(
currentTrip = Some(chosenTrip),
currentTourMode = data.personData.currentTripMode,
restOfCurrentTrip = List()
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand All @@ -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._
Expand All @@ -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
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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,
Expand Down
4 changes: 4 additions & 0 deletions src/main/scala/beam/router/Modes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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

Expand Down
8 changes: 0 additions & 8 deletions src/main/scala/beam/sim/RideHailFleetInitializer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit ef55850

Please sign in to comment.