Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include RH skims by fleet #3802

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,22 @@ trait ChoosesMode {
}
.toIndexedSeq

private val rideHailModeToFleets: Map[ActivitySimPathType, List[String]] =
this.beamServices.beamConfig.beam.agentsim.agents.rideHail.managers
.flatMap(manager =>
manager.supportedModes
.split(',')
.map(_.trim.toLowerCase)
.flatMap(BeamMode.fromString)
.filter(_.isRideHail)
.flatMap(supportedBeamMode =>
determineActivitySimPathTypesFromBeamMode(Some(supportedBeamMode), None)
.map(_ -> manager.name)
)
)
.groupBy(_._1)
.map { case (mode, fleets) => mode -> fleets.map(_._2) }

private def createDummyVehicle(id: String, vehicleTypeId: String, mode: BeamMode, asDriver: Boolean) =
StreetVehicle(
Id.create(id, classOf[BeamVehicle]),
Expand Down Expand Up @@ -1341,12 +1357,15 @@ trait ChoosesMode {
case Some(mode) =>
val currentAct = currentActivity(personData)
val odFailedSkimmerEvent = createFailedODSkimmerEvent(currentAct, nextAct, mode)
val possibleActivitySimModes =
determineActivitySimPathTypesFromBeamMode(choosesModeData.personData.currentTourMode, currentAct)
eventsManager.processEvent(
odFailedSkimmerEvent
)
if (beamServices.beamConfig.beam.exchange.output.activitySimSkimsEnabled) {
val possibleActivitySimModes: Seq[ActivitySimPathType] =
determineActivitySimPathTypesFromBeamMode(
choosesModeData.personData.currentTourMode,
Some(currentAct)
)
createFailedActivitySimSkimmerEvent(odFailedSkimmerEvent, possibleActivitySimModes).foreach(ev =>
eventsManager.processEvent(ev)
)
Expand Down Expand Up @@ -1479,15 +1498,33 @@ trait ChoosesMode {
failedODSkimmerEvent: ODSkimmerFailedTripEvent,
modes: Seq[ActivitySimPathType]
): Seq[ActivitySimSkimmerFailedTripEvent] = {
modes.map { pathType =>
ActivitySimSkimmerFailedTripEvent(
origin = failedODSkimmerEvent.origin,
destination = failedODSkimmerEvent.destination,
eventTime = _currentTick.get,
activitySimPathType = pathType,
iterationNumber = beamServices.matsimServices.getIterationNumber,
skimName = beamServices.beamConfig.beam.router.skim.activity_sim_skimmer.name
)
modes.flatMap { pathType =>
rideHailModeToFleets.get(pathType) match {
case Some(fleets) =>
fleets.map(fleet =>
ActivitySimSkimmerFailedTripEvent(
origin = failedODSkimmerEvent.origin,
destination = failedODSkimmerEvent.destination,
eventTime = _currentTick.get,
activitySimPathType = pathType,
fleet = Some(fleet),
iterationNumber = beamServices.matsimServices.getIterationNumber,
skimName = beamServices.beamConfig.beam.router.skim.activity_sim_skimmer.name
)
)
case _ =>
Seq(
ActivitySimSkimmerFailedTripEvent(
origin = failedODSkimmerEvent.origin,
destination = failedODSkimmerEvent.destination,
eventTime = _currentTick.get,
activitySimPathType = pathType,
fleet = None,
iterationNumber = beamServices.matsimServices.getIterationNumber,
skimName = beamServices.beamConfig.beam.router.skim.activity_sim_skimmer.name
)
)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,10 @@ class RideHailMaster(
responsesInRandomOrder.filter(_.travelProposal.exists(_.modeOptions.contains(RIDE_HAIL)))
else
responsesInRandomOrder.filter(_.travelProposal.isDefined)
if (availableProposals.isEmpty)
if (availableProposals.isEmpty) {
logger.warn(f"Can't find a driver because no available proposals for request ${request.toString}")
RideHailResponse.dummyWithError(DriverNotFoundError, request)
else
} else
bestResponseType match {
case "MIN_COST" => availableProposals.minBy(findCost(customer, _))
case "MIN_UTILITY" => sampleProposals(customer, availableProposals)
Expand Down
38 changes: 27 additions & 11 deletions src/main/scala/beam/router/skim/ActivitySimPathType.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package beam.router.skim

import beam.agentsim.agents.ridehail.RideHailVehicleId
import beam.router.Modes.BeamMode
import beam.router.Modes.BeamMode._
import beam.router.model.{EmbodiedBeamLeg, EmbodiedBeamTrip}
import beam.router.skim.ActivitySimMetric._
import org.matsim.api.core.v01.population.Activity
Expand All @@ -9,7 +11,7 @@ sealed trait ActivitySimPathType

object ActivitySimPathType {

private def determineCarPathType(): ActivitySimPathType = {
private def determineCarPathTypeAndFleet(trip: EmbodiedBeamTrip): (ActivitySimPathType, Option[String]) = {
// HOV2,
// HOV3,
// SOV,
Expand All @@ -19,7 +21,13 @@ object ActivitySimPathType {

// we can not get the number of passengers because right here we are processing the possible alternatives of trips
// from origin to destination but not the real trips from origin to destination.
SOV
trip.tripClassifier match {
case BeamMode.RIDE_HAIL =>
(TNC_SINGLE, Some(RideHailVehicleId(trip.legs.find(_.isRideHail).get.beamVehicleId).fleetId))
case BeamMode.RIDE_HAIL_POOLED =>
(TNC_SHARED, Some(RideHailVehicleId(trip.legs.find(_.isRideHail).get.beamVehicleId).fleetId))
case _ => (SOV, None)
}
}

private def determineDriveTransitPathType(trip: EmbodiedBeamTrip): ActivitySimPathType = {
Expand Down Expand Up @@ -81,24 +89,24 @@ object ActivitySimPathType {
}
}

def determineTripPathType(trip: EmbodiedBeamTrip): ActivitySimPathType = {
def determineTripPathTypeAndFleet(trip: EmbodiedBeamTrip): (ActivitySimPathType, Option[String]) = {
val allMods = trip.legs.map(_.beamLeg.mode).toSet
val uniqueNotWalkingModes: Set[BeamMode] = allMods.filter { mode =>
isCar(mode) || isWalkTransit(mode)
}

if (uniqueNotWalkingModes.exists(isCar)) {
if (uniqueNotWalkingModes.exists(isWalkTransit)) {
determineDriveTransitPathType(trip)
(determineDriveTransitPathType(trip), None)
} else {
determineCarPathType()
determineCarPathTypeAndFleet(trip)
}
} else if (uniqueNotWalkingModes.exists(isWalkTransit)) {
determineTransitPathType(trip)
(determineTransitPathType(trip), None)
} else if (allMods.contains(BeamMode.WALK) && allMods.size == 1) {
WALK
(WALK, None)
} else {
OTHER
(OTHER, None)
}
}

Expand Down Expand Up @@ -127,6 +135,8 @@ object ActivitySimPathType {
case WLK_LRF_WLK => BeamMode.WALK_TRANSIT
case WLK_TRN_WLK => BeamMode.WALK_TRANSIT
case WALK | OTHER => BeamMode.WALK
case TNC_SINGLE => BeamMode.RIDE_HAIL
case TNC_SHARED => BeamMode.RIDE_HAIL_POOLED
}
}

Expand Down Expand Up @@ -154,9 +164,9 @@ object ActivitySimPathType {

def determineActivitySimPathTypesFromBeamMode(
currentMode: Option[BeamMode],
currentActivity: Activity
currentActivity: Option[Activity]
): Seq[ActivitySimPathType] = {
val currentActivityType = currentActivity.getType.toLowerCase()
val currentActivityType = currentActivity.map(_.getType.toLowerCase())
currentMode match {
case Some(BeamMode.WALK) => Seq(ActivitySimPathType.WALK)
case Some(BeamMode.CAR) =>
Expand Down Expand Up @@ -193,7 +203,7 @@ object ActivitySimPathType {
)
case Some(BeamMode.DRIVE_TRANSIT) =>
currentActivityType match {
case "home" =>
case Some("home") =>
Seq(
ActivitySimPathType.DRV_LOC_WLK,
ActivitySimPathType.DRV_HVY_WLK,
Expand All @@ -210,6 +220,10 @@ object ActivitySimPathType {
ActivitySimPathType.WLK_EXP_DRV
)
}
case Some(BeamMode.RIDE_HAIL) =>
Seq(ActivitySimPathType.TNC_SINGLE)
case Some(BeamMode.RIDE_HAIL_POOLED) =>
Seq(ActivitySimPathType.TNC_SHARED)
case _ =>
Seq.empty[ActivitySimPathType]
}
Expand Down Expand Up @@ -307,6 +321,8 @@ object ActivitySimPathType {
case object HOV3TOLL extends ActivitySimPathType
case object SOV extends ActivitySimPathType
case object SOVTOLL extends ActivitySimPathType
case object TNC_SINGLE extends ActivitySimPathType
case object TNC_SHARED extends ActivitySimPathType
case object WLK_COM_DRV extends ActivitySimPathType
case object WLK_COM_WLK extends ActivitySimPathType
case object WLK_EXP_DRV extends ActivitySimPathType
Expand Down
75 changes: 61 additions & 14 deletions src/main/scala/beam/router/skim/ActivitySimSkimmer.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package beam.router.skim

import beam.router.skim.ActivitySimPathType.{isWalkTransit, WLK_TRN_WLK}
import beam.router.skim.ActivitySimPathType.{isWalkTransit, TNC_SHARED, TNC_SINGLE, WLK_TRN_WLK}
import beam.router.skim.core.{AbstractSkimmer, AbstractSkimmerInternal, AbstractSkimmerKey, AbstractSkimmerReadOnly}
import beam.router.skim.urbansim.ActivitySimOmxWriter
import beam.router.Modes.BeamMode
import beam.router.Modes.BeamMode.{RIDE_HAIL, RIDE_HAIL_POOLED}
import beam.sim.BeamScenario
import beam.sim.config.BeamConfig
import beam.utils.ProfilingUtils
Expand All @@ -21,6 +23,19 @@ class ActivitySimSkimmer @Inject() (matsimServices: MatsimServices, beamScenario
extends AbstractSkimmer(beamConfig, matsimServices.getControlerIO) {

private val config: BeamConfig.Beam.Router.Skim = beamConfig.beam.router.skim

private val allRideHailFleets: Map[BeamMode, List[String]] = beamConfig.beam.agentsim.agents.rideHail.managers
.flatMap(manager =>
manager.supportedModes
.split(',')
.map(_.trim.toLowerCase)
.flatMap(BeamMode.fromString)
.filter(_.isRideHail)
.map(supportedMode => supportedMode -> manager.name)
)
.groupBy(_._1)
.map { case (mode, fleets) => mode -> fleets.map(_._2) }

import ActivitySimSkimmer._

override lazy val readOnlySkim: AbstractSkimmerReadOnly = ActivitySimSkims(beamConfig, beamScenario)
Expand Down Expand Up @@ -156,10 +171,11 @@ class ActivitySimSkimmer @Inject() (matsimServices: MatsimServices, beamScenario
writer: BufferedWriter,
origin: GeoUnit,
destination: GeoUnit,
pathType: ActivitySimPathType
pathType: ActivitySimPathType,
fleet: Option[String] = None
): Unit = {
ActivitySimTimeBin.values.foreach { timeBin =>
val excerptData = getExcerptData(timeBin, origin, destination, pathType)
val excerptData = getExcerptData(timeBin, origin, destination, pathType, fleet)
writer.write(excerptData.toCsvString)
}
}
Expand All @@ -177,7 +193,18 @@ class ActivitySimSkimmer @Inject() (matsimServices: MatsimServices, beamScenario
pathTypes.foreach { pathType =>
origins.foreach { origin =>
destinations.foreach { destination =>
writeSkimRow(writer, origin, destination, pathType)
pathType match {
case TNC_SINGLE =>
allRideHailFleets(RIDE_HAIL).foreach { fleet =>
writeSkimRow(writer, origin, destination, pathType, Some(fleet))
}
case TNC_SHARED =>
allRideHailFleets(RIDE_HAIL_POOLED).foreach { fleet =>
writeSkimRow(writer, origin, destination, pathType, Some(fleet))
}
case _ => writeSkimRow(writer, origin, destination, pathType)
}

}
}
}
Expand All @@ -196,7 +223,8 @@ class ActivitySimSkimmer @Inject() (matsimServices: MatsimServices, beamScenario
timeBin: ActivitySimTimeBin,
pathType: ActivitySimPathType,
origin: String,
destination: String
destination: String,
fleet: Option[String]
)
ProfilingUtils.timed("Writing skims that are created during simulation ", x => logger.info(x)) {
val excerptData = currentSkim
Expand All @@ -214,10 +242,17 @@ class ActivitySimSkimmer @Inject() (matsimServices: MatsimServices, beamScenario
}
.groupBy { case (key, _) =>
val asTimeBin = ActivitySimTimeBin.toTimeBin(key.hour)
ActivitySimKey(asTimeBin, key.pathType, key.origin, key.destination)
ActivitySimKey(asTimeBin, key.pathType, key.origin, key.destination, key.fleet)
}
.map { case (key, skimMap) =>
weightedData(key.timeBin.entryName, key.origin, key.destination, key.pathType, skimMap.values.toList)
weightedData(
key.timeBin.entryName,
key.origin,
key.destination,
key.pathType,
key.fleet,
skimMap.values.toList
)
}

val writeResult = if (config.activity_sim_skimmer.fileOutputFormat.trim.equalsIgnoreCase("csv")) {
Expand Down Expand Up @@ -248,7 +283,8 @@ class ActivitySimSkimmer @Inject() (matsimServices: MatsimServices, beamScenario
timeBin: ActivitySimTimeBin,
origin: GeoUnit,
destination: GeoUnit,
pathType: ActivitySimPathType
pathType: ActivitySimPathType,
maybeFleetName: Option[String] = None
): Option[ExcerptData] = {
if (pathType == ActivitySimPathType.WALK && timeBin != ActivitySimTimeBin.EARLY_AM) {
None
Expand All @@ -260,7 +296,7 @@ class ActivitySimSkimmer @Inject() (matsimServices: MatsimServices, beamScenario
if (individualSkims.isEmpty) {
None
} else {
Some(weightedData(timeBin.toString, origin.id, destination.id, pathType, individualSkims))
Some(weightedData(timeBin.toString, origin.id, destination.id, pathType, maybeFleetName, individualSkims))
}
}
}
Expand All @@ -270,6 +306,7 @@ class ActivitySimSkimmer @Inject() (matsimServices: MatsimServices, beamScenario
originId: String,
destinationId: String,
pathType: ActivitySimPathType,
fleetName: Option[String],
individualSkims: List[ActivitySimSkimmerInternal]
) = {
val weights = individualSkims.map(sk => sk.observations)
Expand Down Expand Up @@ -308,6 +345,7 @@ class ActivitySimSkimmer @Inject() (matsimServices: MatsimServices, beamScenario
ExcerptData(
timePeriodString = timePeriodString,
pathType = pathType,
fleetName = fleetName.getOrElse(""),
originId = originId,
destinationId = destinationId,
weightedTotalTime = weightedTotalTime,
Expand Down Expand Up @@ -335,12 +373,14 @@ class ActivitySimSkimmer @Inject() (matsimServices: MatsimServices, beamScenario
timeBin: ActivitySimTimeBin,
origin: GeoUnit,
destination: GeoUnit,
pathType: ActivitySimPathType
pathType: ActivitySimPathType,
maybeFleetName: Option[String]
): ExcerptData = {
getExcerptDataOption(timeBin, origin, destination, pathType).getOrElse(
getExcerptDataOption(timeBin, origin, destination, pathType, maybeFleetName).getOrElse(
ExcerptData(
timeBin.toString,
pathType,
maybeFleetName.getOrElse(""),
origin.id,
destination.id,
0,
Expand Down Expand Up @@ -370,9 +410,14 @@ object ActivitySimSkimmer extends LazyLogging {
case class ActivitySimSkimmerODKey(origin: String, destination: String)
case class ActivitySimSkimmerPathHourKey(pathType: ActivitySimPathType, hour: Int)

case class ActivitySimSkimmerKey(hour: Int, pathType: ActivitySimPathType, origin: String, destination: String)
extends AbstractSkimmerKey {
override def toCsv: String = hour + "," + pathType + "," + origin + "," + destination
case class ActivitySimSkimmerKey(
hour: Int,
pathType: ActivitySimPathType,
origin: String,
destination: String,
fleet: Option[String] = None
) extends AbstractSkimmerKey {
override def toCsv: String = hour + "," + pathType + "," + fleet.getOrElse("") + "," + origin + "," + destination
}

case class ActivitySimSkimmerInternal(
Expand Down Expand Up @@ -413,6 +458,7 @@ object ActivitySimSkimmer extends LazyLogging {
case class ExcerptData(
timePeriodString: String,
pathType: ActivitySimPathType,
fleetName: String,
originId: String,
destinationId: String,
weightedTotalTime: Double,
Expand Down Expand Up @@ -488,6 +534,7 @@ object ActivitySimSkimmer extends LazyLogging {
val csvHeaderSeq: Seq[String] = Seq(
"timePeriod",
"pathType",
"fleetName",
"origin",
"destination",
"TIME_minutes",
Expand Down
Loading