Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop' into do/#3441-current-t…
Browse files Browse the repository at this point in the history
…rip-tour-mode

# Conflicts:
#	src/main/scala/beam/agentsim/agents/modalbehaviors/ChoosesMode.scala
  • Loading branch information
dimaopen committed Mar 22, 2022
2 parents 4d2e375 + 676c687 commit 7cfbc79
Show file tree
Hide file tree
Showing 16 changed files with 454 additions and 124 deletions.
336 changes: 308 additions & 28 deletions docs/inputs.rst

Large diffs are not rendered by default.

10 changes: 7 additions & 3 deletions src/main/java/beam/agentsim/events/ModeChoiceEvent.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class ModeChoiceEvent extends Event implements HasPersonId {
public final static String ATTRIBUTE_LEG_VEHICLE_IDS = "legVehicleIds";
public final static String ATTRIBUTE_CURRENT_ACTIVITY = "currentActivity";
public final static String ATTRIBUTE_NEXT_ACTIVITY = "nextActivity";
public final static String ATTRIBUTE_TRIP_ID = "tripId";

public final EmbodiedBeamTrip chosenTrip;
public final Id<Person> personId;
Expand All @@ -41,10 +42,11 @@ public class ModeChoiceEvent extends Event implements HasPersonId {
public final Integer tourIndex;
public final String currentActivity;
public final String nextActivity;
public final String tripId;

public ModeChoiceEvent(double time, Id<Person> personId, String chosenMode, String currentTourMode, Double expectedMaxUtility,
String linkId, String availableAlternatives, Boolean vehAvailable, Double length,
Integer tourIndex, EmbodiedBeamTrip chosenTrip, String currentActivity, String nextActivity) {
Integer tourIndex, EmbodiedBeamTrip chosenTrip, String currentActivity, String nextActivity, String tripId) {
super(time);

this.personId = personId;
Expand All @@ -59,6 +61,7 @@ public ModeChoiceEvent(double time, Id<Person> personId, String chosenMode, Stri
this.chosenTrip = chosenTrip;
this.currentActivity = currentActivity;
this.nextActivity = nextActivity;
this.tripId = tripId;
}

public static ModeChoiceEvent apply(Event event) {
Expand All @@ -76,8 +79,8 @@ public static ModeChoiceEvent apply(Event event) {
Integer.parseInt(attr.get(ATTRIBUTE_TOUR_INDEX)),
null,
attr.get(ATTRIBUTE_CURRENT_ACTIVITY),
attr.get(ATTRIBUTE_NEXT_ACTIVITY)
);
attr.get(ATTRIBUTE_NEXT_ACTIVITY),
attr.get(ATTRIBUTE_TRIP_ID));
}
return (ModeChoiceEvent) event;
}
Expand All @@ -100,6 +103,7 @@ public Map<String, String> getAttributes() {
}
attr.put(ATTRIBUTE_CURRENT_ACTIVITY, currentActivity);
attr.put(ATTRIBUTE_NEXT_ACTIVITY, nextActivity);
attr.put(ATTRIBUTE_TRIP_ID, tripId);
return attr;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public void writeEvent(Event event) {
for (String attribute : attributeKeys) {
if (!attributeToColumnIndexMapping.containsKey(attribute)) {
if (this.eventTypeToLog == null || !attribute.equals(Event.ATTRIBUTE_TYPE)) {
DebugLib.stopSystemAndReportInconsistency("unkown attribute:" + attribute + ";class:" + event.getClass());
DebugLib.stopSystemAndReportInconsistency("unknown attribute:" + attribute + ";class:" + event.getClass());
}
}
if (this.eventTypeToLog == null || !attribute.equals(Event.ATTRIBUTE_TYPE)) {
Expand Down
65 changes: 62 additions & 3 deletions src/main/python/general_analysis/simulation_health_analysis.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import os
import requests
from glob import glob
from shutil import copyfile



# detectors is a dictionary that consist key as health metric and
# value as lambda function that can detect health metric from line.
# if we need to add more detector then we have to add that detector in this dictionary
Expand All @@ -14,13 +15,63 @@
"stacktrace": lambda line: line.startswith("\tat ")
}
beam_home = os.getcwd()


def handleJavaErrorLine(line):
tokens = line.split("\"")
if len(tokens) > 0:
return tokens[1].replace('%s', '')


def handleScalaToken(tokens):
out_result = []
if len(tokens) > 1:
split_error_lines = tokens[1].strip().split('$')
first_word = True
for split_error_line in split_error_lines:
words = split_error_line.strip().replace('\\n', '').split(" ")
word_collector = words if first_word else words[1:]
if first_word:
first_word = False
if len(word_collector) > len(out_result):
out_result = word_collector
return " ".join(out_result)


def handleScalaErrorLine(line):
tokens = line.split("\"")
if "(s\"" in line or "(\ns\"" in line or "(f\"" in line:
return handleScalaToken(tokens)
elif len(tokens) > 1:
return tokens[1]


def detect_all_error_types():
error_list = []
for dir_path, sub_dir_path, source_files in os.walk(beam_home + '/src/main/'):
for source_file in source_files:
if source_file.endswith('.java'):
source = open(dir_path + '/' + source_file, "r")
for line in source:
if 'new RuntimeException' in line or 'new Exception' in line:
error_list.append(handleJavaErrorLine(line))
if source_file.endswith('.scala'):
source = open(dir_path + '/' + source_file, "r")
for line in source:
if 'new RuntimeException' in line or 'new Exception' in line:
error_list.append(handleScalaErrorLine(line))
return error_list


log_file_location = glob(beam_home + "/output/*/*/beamLog.out")
log_file_location.sort(key=lambda x: os.path.getmtime(x), reverse=True)
with open(log_file_location[0]) as file:
file = file.readlines()

matric_log = {}
stacktrace_count = 0
error_types = detect_all_error_types()

for line in file:
# treating stacktrace detector specially because 1 stacktrace consist multiple lines of stacktrace
if detectors["stacktrace"](line):
Expand All @@ -42,9 +93,17 @@
matric_log[key] = matric
break

for error_type in error_types:
if error_type is not None and error_type in line:
matric = matric_log.get(error_type, [])
matric.append(line)
matric_log[error_type] = matric

with open('RunHealthAnalysis.txt', 'w') as file:
for detector in detectors:
file.write(detector+","+str(len(matric_log.get(detector, [])))+"\n")
file.write(detector + "," + str(len(matric_log.get(detector, []))) + "\n")

beam_output_path = os.path.dirname(log_file_location[0])
copyfile('RunHealthAnalysis.txt', beam_output_path+"/runHealthAnalysis.txt")
copyfile('RunHealthAnalysis.txt', beam_output_path + "/runHealthAnalysis.txt")


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
7 changes: 5 additions & 2 deletions src/main/scala/beam/agentsim/agents/PersonAgent.scala
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,6 @@ class PersonAgent(
case Some(fixedDuration) => tick + fixedDuration
case _ => activityEndTime
}

if (lastTickOfSimulation >= tick) {
Math.min(lastTickOfSimulation, endTime)
} else {
Expand Down Expand Up @@ -665,7 +664,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 @@ -153,7 +153,7 @@ trait ChoosesMode {
_,
_,
_,
None | Some(CAR | BIKE | DRIVE_TRANSIT | BIKE_TRANSIT),
plansModeOption @ (None | Some(CAR | BIKE | DRIVE_TRANSIT | BIKE_TRANSIT)),
_,
_,
_,
Expand Down Expand Up @@ -188,11 +188,29 @@ trait ChoosesMode {
_
) =>
implicit val executionContext: ExecutionContext = context.system.dispatcher
requestAvailableVehicles(
vehicleFleets,
currentLocation,
_experiencedBeamPlan.activities(currentActivityIndex)
) pipeTo self
plansModeOption match {
case Some(CAR | DRIVE_TRANSIT) =>
requestAvailableVehicles(
vehicleFleets,
currentLocation,
_experiencedBeamPlan.activities(currentActivityIndex),
Some(VehicleCategory.Car)
) pipeTo self
case Some(BIKE | BIKE_TRANSIT) =>
requestAvailableVehicles(
vehicleFleets,
currentLocation,
_experiencedBeamPlan.activities(currentActivityIndex),
Some(VehicleCategory.Bike)
) pipeTo self
case _ =>
requestAvailableVehicles(
vehicleFleets,
currentLocation,
_experiencedBeamPlan.activities(currentActivityIndex)
) pipeTo self
}

// Otherwise, send empty list to self
case _ =>
self ! MobilityStatusResponse(Vector(), getCurrentTriggerIdOrGenerate)
Expand Down Expand Up @@ -246,8 +264,11 @@ trait ChoosesMode {

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 @@ -1396,23 +1417,25 @@ trait ChoosesMode {
)
}

val tripId = Option(
_experiencedBeamPlan.activities(data.personData.currentActivityIndex).getAttributes.getAttribute("trip_id")
).getOrElse("").toString

val modeChoiceEvent = new ModeChoiceEvent(
tick,
id,
chosenTrip.tripClassifier.value,
data.personData.currentTripMode.map(_.value).getOrElse(""),
data.expectedMaxUtilityOfLatestChoice.getOrElse[Double](Double.NaN),
_experiencedBeamPlan
.activities(data.personData.currentActivityIndex)
.getLinkId
.toString,
_experiencedBeamPlan.activities(data.personData.currentActivityIndex).getLinkId.toString,
data.availableAlternatives.get,
data.availablePersonalStreetVehicles.nonEmpty,
chosenTrip.legs.view.map(_.beamLeg.travelPath.distanceInM).sum,
_experiencedBeamPlan.tourIndexOfElement(nextActivity(data.personData).get),
chosenTrip,
_experiencedBeamPlan.activities(data.personData.currentActivityIndex).getType,
nextActivity(data.personData).get.getType
nextActivity(data.personData).get.getType,
tripId
)
eventsManager.processEvent(modeChoiceEvent)

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 @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ object ChoosesParking {
)
eventsManager.processEvent(parkEvent) // nextLeg.endTime -> to fix repeated path traversal
restOfTrip.foreach { legs =>
if (legs.size >= 2 && legs(0).beamLeg.mode == BeamMode.CAR && legs(1).beamLeg.mode == BeamMode.WALK) {
val parkingSkimmerEvent = createParkingSkimmerEvent(tick, tazTreeMap, nextActivity, stall, legs)
if (legs.size >= 2 && legs.head.beamLeg.mode == BeamMode.CAR && legs(1).beamLeg.mode == BeamMode.WALK) {
val parkingSkimmerEvent = createParkingSkimmerEvent(tick, geo, tazTreeMap, nextActivity, stall, legs)
eventsManager.processEvent(parkingSkimmerEvent)
val freightRequestType =
nextActivity.flatMap(activity =>
Expand Down Expand Up @@ -121,14 +121,16 @@ object ChoosesParking {

private def createParkingSkimmerEvent(
tick: Int,
geo: GeoUtils,
tazTreeMap: TAZTreeMap,
nextActivity: Option[Activity],
stall: ParkingStall,
restOfTrip: List[EmbodiedBeamLeg]
): ParkingSkimmerEvent = {
require(restOfTrip.size >= 2, "Rest of trip must consist of two legs at least: current car leg, walk leg")
val walkLeg = restOfTrip(1)
val tazId = tazTreeMap.getTAZ(walkLeg.beamLeg.travelPath.endPoint.loc).tazId
val tripEndPointUTMLocation = geo.wgs2Utm(walkLeg.beamLeg.travelPath.endPoint.loc)
val tazId = tazTreeMap.getTAZ(tripEndPointUTMLocation).tazId
val chargerType = stall.chargingPointType match {
case Some(chargingType) if ChargingPointType.getChargingPointCurrent(chargingType) == ElectricCurrentType.DC =>
ChargerType.DCFastCharger
Expand Down
Loading

0 comments on commit 7cfbc79

Please sign in to comment.