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 develop
  • Loading branch information
Xuan-1998 committed Mar 28, 2022
2 parents 7806b3e + de1684a commit aa2d0c1
Show file tree
Hide file tree
Showing 8 changed files with 232 additions and 292 deletions.
95 changes: 62 additions & 33 deletions src/main/scala/beam/agentsim/agents/PersonAgent.scala
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ object PersonAgent {
restOfCurrentTrip: List[EmbodiedBeamLeg] = List(),
currentVehicle: VehicleStack = Vector(),
currentTourMode: Option[BeamMode] = None,
currentTripMode: Option[BeamMode] = None,
currentTourPersonalVehicle: Option[Id[BeamVehicle]] = None,
passengerSchedule: PassengerSchedule = PassengerSchedule(),
currentLegPassengerScheduleIndex: Int = 0,
Expand Down Expand Up @@ -285,6 +286,8 @@ object PersonAgent {
case basePersonData: BasePersonData => Some(basePersonData)
case _ => None
}

def atHome(activity: Activity): Boolean = activity.getType.equalsIgnoreCase("home")
}

class PersonAgent(
Expand Down Expand Up @@ -406,7 +409,7 @@ class PersonAgent(
// which is used in place of our real remaining tour distance of 0.0
// which should help encourage residential end-of-day charging
val tomorrowFirstLegDistance =
if (nextAct.getType.toLowerCase == "home") {
if (atHome(nextAct)) {
findFirstCarLegOfTrip(personData) match {
case Some(carLeg) =>
carLeg.beamLeg.travelPath.distanceInM
Expand Down Expand Up @@ -475,6 +478,30 @@ class PersonAgent(
}
}

def isFirstTripWithinTour(personData: BasePersonData, nextAct: Activity): Boolean = {
val (tripIndexOfElement: Int, _) = currentTripIndexWithinTour(personData, nextAct)
tripIndexOfElement == 0
}

def isLastTripWithinTour(personData: BasePersonData, nextAct: Activity): Boolean = {
val (tripIndexOfElement: Int, lastTripIndex: Int) = currentTripIndexWithinTour(personData, nextAct)
tripIndexOfElement == lastTripIndex
}

def isFirstOrLastTripWithinTour(personData: BasePersonData, nextAct: Activity): Boolean = {
val (tripIndexOfElement: Int, lastTripIndex: Int) = currentTripIndexWithinTour(personData, nextAct)
tripIndexOfElement == 0 || tripIndexOfElement == lastTripIndex
}

def currentTripIndexWithinTour(personData: BasePersonData, nextAct: Activity): (Int, Int) = {
val tour = currentTour(personData)
val lastTripIndex = tour.trips.size - 1
val tripIndexOfElement = tour
.tripIndexOfElement(nextAct)
.getOrElse(throw new IllegalArgumentException(s"Element [$nextAct] not found"))
(tripIndexOfElement, lastTripIndex)
}

def currentActivity(data: BasePersonData): Activity =
_experiencedBeamPlan.activities(data.currentActivityIndex)

Expand Down Expand Up @@ -586,15 +613,10 @@ class PersonAgent(
val nextCoord = nextActivity(data).get.getCoord
goto(ChoosingMode) using ChoosesModeData(
personData = data.copy(
// If the mode of the next leg is defined and is CAV, use it, otherwise,
// If we don't have a current tour mode (i.e. are not on a tour aka at home),
// use the mode of the next leg as the new tour mode.
currentTourMode = modeOfNextLeg match {
case Some(CAV) =>
Some(CAV)
case _ =>
data.currentTourMode.orElse(modeOfNextLeg)
},
// We do not stick to current tour mode
// If we have the currentTourPersonalVehicle then we should use it
// use the mode of the next leg as the new trip mode.
currentTripMode = modeOfNextLeg,
numberOfReplanningAttempts = 0,
failedTrips = IndexedSeq.empty,
enrouteData = EnrouteData()
Expand All @@ -611,7 +633,7 @@ class PersonAgent(
when(Teleporting) {
case Event(
TriggerWithId(PersonDepartureTrigger(tick), triggerId),
data @ BasePersonData(_, Some(currentTrip), _, _, _, _, _, _, false, _, _, _, _, _)
data @ BasePersonData(_, Some(currentTrip), _, _, _, _, _, _, _, false, _, _, _, _, _)
) =>
endActivityAndDepart(tick, currentTrip, data)

Expand All @@ -625,7 +647,7 @@ class PersonAgent(

case Event(
TriggerWithId(TeleportationEndsTrigger(tick), triggerId),
data @ BasePersonData(_, Some(currentTrip), _, _, maybeCurrentTourMode, _, _, _, true, _, _, _, _, _)
data @ BasePersonData(_, Some(currentTrip), _, _, _, maybeCurrentTripMode, _, _, _, true, _, _, _, _, _)
) =>
holdTickAndTriggerId(tick, triggerId)

Expand All @@ -638,7 +660,7 @@ class PersonAgent(
startY = currentTrip.legs.head.beamLeg.travelPath.startPoint.loc.getY,
endX = currentTrip.legs.last.beamLeg.travelPath.endPoint.loc.getX,
endY = currentTrip.legs.last.beamLeg.travelPath.endPoint.loc.getY,
currentTourMode = maybeCurrentTourMode.map(_.value)
currentTourMode = maybeCurrentTripMode.map(_.value)
)
eventsManager.processEvent(teleportationEvent)

Expand All @@ -657,7 +679,7 @@ class PersonAgent(
*/
case Event(
TriggerWithId(PersonDepartureTrigger(tick), triggerId),
data @ BasePersonData(_, Some(currentTrip), _, _, _, _, _, _, false, _, _, _, _, _)
data @ BasePersonData(_, Some(currentTrip), _, _, _, _, _, _, _, false, _, _, _, _, _)
) =>
endActivityAndDepart(tick, currentTrip, data)

Expand All @@ -666,7 +688,7 @@ class PersonAgent(

case Event(
TriggerWithId(PersonDepartureTrigger(tick), triggerId),
BasePersonData(_, _, restOfCurrentTrip, _, _, _, _, _, true, _, _, _, _, _)
BasePersonData(_, _, restOfCurrentTrip, _, _, _, _, _, _, true, _, _, _, _, _)
) =>
// We're coming back from replanning, i.e. we are already on the trip, so we don't throw a departure event
logDebug(s"replanned to leg ${restOfCurrentTrip.head}")
Expand Down Expand Up @@ -722,7 +744,7 @@ class PersonAgent(
val currentCoord = beamServices.geo.wgs2Utm(data.restOfCurrentTrip.head.beamLeg.travelPath.startPoint).loc
val nextCoord = nextActivity(data).get.getCoord
goto(ChoosingMode) using ChoosesModeData(
data.copy(currentTourMode = None, numberOfReplanningAttempts = data.numberOfReplanningAttempts + 1),
data.copy(currentTripMode = None, numberOfReplanningAttempts = data.numberOfReplanningAttempts + 1),
currentLocation = SpaceTime(
currentCoord,
tick
Expand All @@ -741,7 +763,7 @@ class PersonAgent(
// TRANSIT FAILURE
case Event(
ReservationResponse(Left(firstErrorResponse), _),
data @ BasePersonData(_, _, nextLeg :: _, _, _, _, _, _, _, _, _, _, _, _)
data @ BasePersonData(_, _, nextLeg :: _, _, _, _, _, _, _, _, _, _, _, _, _)
) =>
logDebug(s"replanning because ${firstErrorResponse.errorCode}")

Expand Down Expand Up @@ -815,7 +837,7 @@ class PersonAgent(
// RIDE HAIL FAILURE
case Event(
response @ RideHailResponse(_, _, Some(error), _, _),
data @ BasePersonData(_, _, _, _, _, _, _, _, _, _, _, _, _, _)
data: BasePersonData
) =>
handleFailedRideHailReservation(error, response, data)
}
Expand All @@ -826,7 +848,7 @@ class PersonAgent(
*/
case Event(
TriggerWithId(BoardVehicleTrigger(tick, vehicleToEnter), triggerId),
data @ BasePersonData(_, _, currentLeg :: _, currentVehicle, _, _, _, _, _, _, _, _, _, _)
data @ BasePersonData(_, _, currentLeg :: _, currentVehicle, _, _, _, _, _, _, _, _, _, _, _)
) =>
logDebug(s"PersonEntersVehicle: $vehicleToEnter @ $tick")
eventsManager.processEvent(new PersonEntersVehicleEvent(tick, id, vehicleToEnter))
Expand Down Expand Up @@ -859,7 +881,7 @@ class PersonAgent(
*/
case Event(
TriggerWithId(AlightVehicleTrigger(tick, vehicleToExit, energyConsumedOption), triggerId),
data @ BasePersonData(_, _, _ :: restOfCurrentTrip, currentVehicle, _, _, _, _, _, _, _, _, _, _)
data @ BasePersonData(_, _, _ :: restOfCurrentTrip, currentVehicle, _, _, _, _, _, _, _, _, _, _, _)
) if vehicleToExit.equals(currentVehicle.head) =>
updateFuelConsumed(energyConsumedOption)
logDebug(s"PersonLeavesVehicle: $vehicleToExit @ $tick")
Expand Down Expand Up @@ -936,6 +958,7 @@ class PersonAgent(
_,
_,
_,
_,
currentCost,
_,
_,
Expand Down Expand Up @@ -980,6 +1003,7 @@ class PersonAgent(
goto(ChoosingMode) using ChoosesModeData(
basePersonData.copy(
currentTourMode = None, // Have to give up my mode as well, perhaps there's no option left for driving.
currentTripMode = None,
currentTourPersonalVehicle = None,
numberOfReplanningAttempts = basePersonData.numberOfReplanningAttempts + 1
),
Expand Down Expand Up @@ -1076,6 +1100,7 @@ class PersonAgent(
_,
_,
_,
_,
_
)
) if nextLeg.asDriver =>
Expand Down Expand Up @@ -1170,7 +1195,7 @@ class PersonAgent(
nextState

// TRANSIT but too late
case Event(StateTimeout, data @ BasePersonData(_, _, nextLeg :: _, _, _, _, _, _, _, _, _, _, _, _))
case Event(StateTimeout, data @ BasePersonData(_, _, nextLeg :: _, _, _, _, _, _, _, _, _, _, _, _, _))
if nextLeg.beamLeg.mode.isTransit && nextLeg.beamLeg.startTime < _currentTick.get =>
// We've missed the bus. This occurs when something takes longer than planned (based on the
// initial inquiry). So we replan but change tour mode to WALK_TRANSIT since we've already done our non-transit
Expand All @@ -1185,15 +1210,15 @@ class PersonAgent(
val nextCoord = nextActivity(data).get.getCoord
goto(ChoosingMode) using ChoosesModeData(
personData = data
.copy(currentTourMode = Some(WALK_TRANSIT), numberOfReplanningAttempts = data.numberOfReplanningAttempts + 1),
.copy(currentTripMode = Some(WALK_TRANSIT), numberOfReplanningAttempts = data.numberOfReplanningAttempts + 1),
currentLocation = SpaceTime(currentCoord, _currentTick.get),
isWithinTripReplanning = true,
excludeModes =
if (canUseCars(currentCoord, nextCoord)) Vector.empty
else Vector(BeamMode.RIDE_HAIL, BeamMode.CAR, BeamMode.CAV)
)
// TRANSIT
case Event(StateTimeout, BasePersonData(_, _, nextLeg :: _, _, _, _, _, _, _, _, _, _, _, _))
case Event(StateTimeout, BasePersonData(_, _, nextLeg :: _, _, _, _, _, _, _, _, _, _, _, _, _))
if nextLeg.beamLeg.mode.isTransit =>
val resRequest = TransitReservationRequest(
nextLeg.beamLeg.travelPath.transitStops.get.fromIdx,
Expand All @@ -1204,7 +1229,7 @@ class PersonAgent(
TransitDriverAgent.selectByVehicleId(nextLeg.beamVehicleId) ! resRequest
goto(WaitingForReservationConfirmation)
// RIDE_HAIL
case Event(StateTimeout, BasePersonData(_, _, nextLeg :: tailOfCurrentTrip, _, _, _, _, _, _, _, _, _, _, _))
case Event(StateTimeout, BasePersonData(_, _, nextLeg :: tailOfCurrentTrip, _, _, _, _, _, _, _, _, _, _, _, _))
if nextLeg.isRideHail =>
val legSegment = nextLeg :: tailOfCurrentTrip.takeWhile(leg => leg.beamVehicleId == nextLeg.beamVehicleId)

Expand Down Expand Up @@ -1232,7 +1257,7 @@ class PersonAgent(
goto(WaitingForReservationConfirmation)
// CAV but too late
// TODO: Refactor so it uses literally the same code block as transit
case Event(StateTimeout, data @ BasePersonData(_, _, nextLeg :: _, _, _, _, _, _, _, _, _, _, _, _))
case Event(StateTimeout, data @ BasePersonData(_, _, nextLeg :: _, _, _, _, _, _, _, _, _, _, _, _, _))
if nextLeg.beamLeg.startTime < _currentTick.get =>
// We've missed the CAV. This occurs when something takes longer than planned (based on the
// initial inquiry). So we replan but change tour mode to WALK_TRANSIT since we've already done our non-transit
Expand All @@ -1247,7 +1272,7 @@ class PersonAgent(
val nextCoord = nextActivity(data).get.getCoord
goto(ChoosingMode) using ChoosesModeData(
personData = data
.copy(currentTourMode = Some(WALK_TRANSIT), numberOfReplanningAttempts = data.numberOfReplanningAttempts + 1),
.copy(currentTripMode = Some(WALK_TRANSIT), numberOfReplanningAttempts = data.numberOfReplanningAttempts + 1),
currentLocation = SpaceTime(currentCoord, _currentTick.get),
isWithinTripReplanning = true,
excludeModes =
Expand All @@ -1256,7 +1281,7 @@ class PersonAgent(
)
// CAV
// TODO: Refactor so it uses literally the same code block as transit
case Event(StateTimeout, BasePersonData(_, _, nextLeg :: tailOfCurrentTrip, _, _, _, _, _, _, _, _, _, _, _)) =>
case Event(StateTimeout, BasePersonData(_, _, nextLeg :: tailOfCurrentTrip, _, _, _, _, _, _, _, _, _, _, _, _)) =>
val legSegment = nextLeg :: tailOfCurrentTrip.takeWhile(leg => leg.beamVehicleId == nextLeg.beamVehicleId)
val resRequest = ReservationRequest(
legSegment.head.beamLeg,
Expand All @@ -1276,7 +1301,8 @@ class PersonAgent(
_,
_,
_,
currentTourMode @ Some(HOV2_TELEPORTATION | HOV3_TELEPORTATION),
_,
Some(HOV2_TELEPORTATION | HOV3_TELEPORTATION),
_,
_,
_,
Expand Down Expand Up @@ -1316,7 +1342,8 @@ class PersonAgent(
currentTrip = None,
restOfCurrentTrip = List(),
currentTourPersonalVehicle = None,
currentTourMode = if (activity.getType.equals("Home")) None else currentTourMode,
currentTourMode = if (atHome(activity)) None else data.currentTourMode,
currentTripMode = None,
hasDeparted = false
)
case None =>
Expand All @@ -1334,6 +1361,7 @@ class PersonAgent(
_,
_,
currentTourMode,
_,
currentTourPersonalVehicle,
_,
_,
Expand Down Expand Up @@ -1404,7 +1432,7 @@ class PersonAgent(
currentTourPersonalVehicle = currentTourPersonalVehicle match {
case Some(personalVehId) =>
val personalVeh = beamVehicles(personalVehId).asInstanceOf[ActualVehicle].vehicle
if (activity.getType.equals("Home")) {
if (atHome(activity)) {
potentiallyChargingBeamVehicles.put(personalVeh.id, beamVehicles(personalVeh.id))
beamVehicles -= personalVeh.id
personalVeh.getManager.get ! ReleaseVehicle(personalVeh, triggerId)
Expand All @@ -1415,7 +1443,8 @@ class PersonAgent(
case None =>
None
},
currentTourMode = if (activity.getType.equals("Home")) None else currentTourMode,
currentTourMode = if (atHome(activity)) None else currentTourMode,
currentTripMode = None,
hasDeparted = false
)
case None =>
Expand Down Expand Up @@ -1489,7 +1518,7 @@ class PersonAgent(
}

def getReplanningReasonFrom(data: BasePersonData, prefix: String): String = {
data.currentTourMode
data.currentTripMode
.collect { case mode =>
s"$prefix $mode"
}
Expand Down Expand Up @@ -1563,7 +1592,7 @@ class PersonAgent(
handleBoardOrAlightOutOfPlace
case Event(
TriggerWithId(BoardVehicleTrigger(_, vehicleId), triggerId),
BasePersonData(_, _, _, currentVehicle, _, _, _, _, _, _, _, _, _, _)
BasePersonData(_, _, _, currentVehicle, _, _, _, _, _, _, _, _, _, _, _)
) if currentVehicle.nonEmpty && currentVehicle.head.equals(vehicleId) =>
log.debug("Person {} in state {} received Board for vehicle that he is already on, ignoring...", id, stateName)
stay() replying CompletionNotice(triggerId, Vector())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,8 @@ object HouseholdActor {
val homeCoordFromPlans = household.members
.flatMap(person =>
person.getSelectedPlan.getPlanElements.asScala.flatMap {
case act: Activity if act.getType == "Home" => Some(act.getCoord)
case _ => None
case act: Activity if PersonAgent.atHome(act) => Some(act.getCoord)
case _ => None
}
)
.headOption
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import akka.util.Timeout
import beam.agentsim.Resource.NotifyVehicleIdle
import beam.agentsim.agents.BeamAgent.Finish
import beam.agentsim.agents.InitializeTrigger
import beam.agentsim.agents.PersonAgent.atHome
import beam.agentsim.agents.household.HouseholdActor._
import beam.agentsim.agents.household.HouseholdFleetManager.ResolvedParkingResponses
import beam.agentsim.agents.modalbehaviors.DrivesVehicle.ActualVehicle
Expand Down Expand Up @@ -104,7 +105,7 @@ class HouseholdFleetManager(
case GetVehicleTypes(triggerId) =>
sender() ! VehicleTypesResponse(vehicles.values.map(_.beamVehicleType).toSet, triggerId)

case MobilityStatusInquiry(personId, whenWhere, _, requireVehicleCategoryAvailable, triggerId) =>
case MobilityStatusInquiry(personId, whenWhere, originActivity, requireVehicleCategoryAvailable, triggerId) =>
{
for {
neededVehicleCategory <- requireVehicleCategoryAvailable
Expand Down Expand Up @@ -157,13 +158,15 @@ class HouseholdFleetManager(
}
}.getOrElse {
availableVehicles = availableVehicles match {
case firstVehicle :: rest =>
//in case of replanning because of TRANSIT failure WALK_TRANSIT is used
//but we may want to introduce maxWalkingDistance and check that the agent is close enough to the vehicle
case firstVehicle :: rest if atHome(originActivity) =>
logger.debug("Vehicle {} is now taken", firstVehicle.id)
firstVehicle.becomeDriver(sender)
sender() ! MobilityStatusResponse(Vector(ActualVehicle(firstVehicle)), triggerId)
rest
case Nil =>
logger.debug(s"Not returning vehicle because no default is defined")
case _ =>
logger.debug(s"Not returning vehicle because no default is defined or agent is not at home")
sender() ! MobilityStatusResponse(Vector(), triggerId)
Nil
}
Expand Down
Loading

0 comments on commit aa2d0c1

Please sign in to comment.