-
Notifications
You must be signed in to change notification settings - Fork 57
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
Current trip mode basing on current tour mode #3476
base: develop
Are you sure you want to change the base?
Changes from all commits
c40970f
4d2e375
7cfbc79
a58eef5
93566b6
691456f
6d063a9
de1684a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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, | ||
|
@@ -285,6 +286,8 @@ object PersonAgent { | |
case basePersonData: BasePersonData => Some(basePersonData) | ||
case _ => None | ||
} | ||
|
||
def atHome(activity: Activity): Boolean = activity.getType.equalsIgnoreCase("home") | ||
} | ||
|
||
class PersonAgent( | ||
|
@@ -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 | ||
|
@@ -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) | ||
|
||
|
@@ -586,15 +613,10 @@ class PersonAgent( | |
val nextCoord = nextActivity(data).get.getCoord | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now that I look at it, I wonder if the definition of
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replayed in the comment bellow. |
||
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm wondering if here we can make use of the So, I'm wondering if something like
would get the current tour mode, and we could do something similar with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replayed in the comment bellow. |
||
// 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() | ||
|
@@ -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) | ||
|
||
|
@@ -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) | ||
|
||
|
@@ -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) | ||
|
||
|
@@ -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) | ||
|
||
|
@@ -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}") | ||
|
@@ -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 | ||
|
@@ -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}") | ||
|
||
|
@@ -815,7 +837,7 @@ class PersonAgent( | |
// RIDE HAIL FAILURE | ||
case Event( | ||
response @ RideHailResponse(_, _, Some(error), _, _), | ||
data @ BasePersonData(_, _, _, _, _, _, _, _, _, _, _, _, _, _) | ||
data: BasePersonData | ||
) => | ||
handleFailedRideHailReservation(error, response, data) | ||
} | ||
|
@@ -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)) | ||
|
@@ -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") | ||
|
@@ -936,6 +958,7 @@ class PersonAgent( | |
_, | ||
_, | ||
_, | ||
_, | ||
currentCost, | ||
_, | ||
_, | ||
|
@@ -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 | ||
), | ||
|
@@ -1076,6 +1100,7 @@ class PersonAgent( | |
_, | ||
_, | ||
_, | ||
_, | ||
_ | ||
) | ||
) if nextLeg.asDriver => | ||
|
@@ -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 | ||
|
@@ -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, | ||
|
@@ -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) | ||
|
||
|
@@ -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 | ||
|
@@ -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 = | ||
|
@@ -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, | ||
|
@@ -1276,7 +1301,8 @@ class PersonAgent( | |
_, | ||
_, | ||
_, | ||
currentTourMode @ Some(HOV2_TELEPORTATION | HOV3_TELEPORTATION), | ||
_, | ||
Some(HOV2_TELEPORTATION | HOV3_TELEPORTATION), | ||
_, | ||
_, | ||
_, | ||
|
@@ -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 => | ||
|
@@ -1334,6 +1361,7 @@ class PersonAgent( | |
_, | ||
_, | ||
currentTourMode, | ||
_, | ||
currentTourPersonalVehicle, | ||
_, | ||
_, | ||
|
@@ -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) | ||
|
@@ -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 => | ||
|
@@ -1489,7 +1518,7 @@ class PersonAgent( | |
} | ||
|
||
def getReplanningReasonFrom(data: BasePersonData, prefix: String): String = { | ||
data.currentTourMode | ||
data.currentTripMode | ||
.collect { case mode => | ||
s"$prefix $mode" | ||
} | ||
|
@@ -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()) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
|
@@ -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 | ||
|
@@ -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) => | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Providing a private vehicle only when the person is at home might be a wrong idea. It may lead to increased number of "Long waling trips". |
||
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 | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering if we could replace this check with instead checking if the current activity == home. I'm thinking of a case where someone did something like home -> work -> home -> shop -> home. We'd want them to be able to pick up their car for the second home -> shop -> home tour, for instance
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Later edit -- if we rely on the Tour class in BeamPlan this gets easier, I think
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tours are created basing on "Home" activity:
beam/src/main/scala/beam/agentsim/agents/planning/BeamPlan.scala
Line 118 in cb98851
So I think it's generally the same (current activity == home and isFirstTripWithinTour).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That
isFirstTripWithinTour
method is not used anywhere and is kept for symmetry.