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

Cs/#1082 refine analysis #1109

Merged
merged 5 commits into from
Jan 5, 2019
Merged
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 @@ -232,6 +232,7 @@ class RideHailManager(
new RideHailModifyPassengerScheduleManager(
log,
self,
this,
scheduler,
beamServices.beamConfig
)
Expand Down Expand Up @@ -525,7 +526,6 @@ class RideHailManager(
triggersToSchedule,
tick
)
if (modifyPassengerScheduleManager.numberPendingModifyPassengerScheduleAcks == 0) cleanUp
case Some(requestId) =>
// Some here means this is part of a reservation / dispatch of vehicle to a customer
log.debug("modifyPassengerScheduleAck received, completing reservation {}", modifyPassengerScheduleAck)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ import scala.collection.mutable

class RideHailModifyPassengerScheduleManager(
val log: LoggingAdapter,
val rideHailManager: ActorRef,
val rideHailManagerRef: ActorRef,
val rideHailManager: RideHailManager,
val scheduler: ActorRef,
val beamConfig: BeamConfig
) extends HasTickAndTrigger {
Expand Down Expand Up @@ -83,7 +84,7 @@ class RideHailModifyPassengerScheduleManager(
we send a resume message to the agent. This puts the driver back to state driving, so that the reservation
interrupt is received when the agent is in state driving. */
if (reply.isInstanceOf[InterruptedWhileDriving]) {
modifyStatus.rideHailAgent.tell(Resume(), rideHailManager)
modifyStatus.rideHailAgent.tell(Resume(), rideHailManagerRef)
}
case SingleReservation =>
// process reservation interrupt confirmation
Expand Down Expand Up @@ -118,10 +119,10 @@ class RideHailModifyPassengerScheduleManager(
modifyStatus: RideHailModifyPassengerScheduleStatus,
stopDriving: Boolean
): Unit = {
if (stopDriving) modifyStatus.rideHailAgent.tell(StopDriving(modifyStatus.tick.toInt), rideHailManager)
if (stopDriving) modifyStatus.rideHailAgent.tell(StopDriving(modifyStatus.tick.toInt), rideHailManagerRef)
resourcesNotCheckedIn_onlyForDebugging += modifyStatus.vehicleId
modifyStatus.rideHailAgent.tell(modifyStatus.modifyPassengerSchedule, rideHailManager)
modifyStatus.rideHailAgent.tell(Resume(), rideHailManager)
modifyStatus.rideHailAgent.tell(modifyStatus.modifyPassengerSchedule, rideHailManagerRef)
modifyStatus.rideHailAgent.tell(Resume(), rideHailManagerRef)
modifyStatus.status = InterruptMessageStatus.MODIFY_PASSENGER_SCHEDULE_SENT
}

Expand Down Expand Up @@ -164,8 +165,13 @@ class RideHailModifyPassengerScheduleManager(
allTriggersInWave = triggersToSchedule ++ allTriggersInWave

if (numberPendingModifyPassengerScheduleAcks == 0) {
log.debug("sendCompletionAndScheduleNewTimeout 165")
log.debug(
"sendCompletionAndScheduleNewTimeout from line 167 @ {} with trigger {}",
_currentTick,
_currentTriggerId
)
sendCompletionAndScheduleNewTimeout(Reposition, tick)
rideHailManager.cleanUp
}
}

Expand Down Expand Up @@ -207,8 +213,8 @@ class RideHailModifyPassengerScheduleManager(
// )
// }
scheduler.tell(
CompletionNotice(triggerId, allTriggersInWave :+ ScheduleTrigger(timerTrigger, rideHailManager)),
rideHailManager
CompletionNotice(triggerId, allTriggersInWave :+ ScheduleTrigger(timerTrigger, rideHailManagerRef)),
rideHailManagerRef
)
allTriggersInWave = Vector()
}
Expand Down Expand Up @@ -330,7 +336,7 @@ class RideHailModifyPassengerScheduleManager(
passengerScheduleStatus.status = InterruptMessageStatus.INTERRUPT_SENT
// log.debug("sendInterruptMessage:" + passengerScheduleStatus)
passengerScheduleStatus.rideHailAgent
.tell(Interrupt(passengerScheduleStatus.interruptId, passengerScheduleStatus.tick), rideHailManager)
.tell(Interrupt(passengerScheduleStatus.interruptId, passengerScheduleStatus.tick), rideHailManagerRef)
}

def isPendingReservationEnding(
Expand Down
66 changes: 10 additions & 56 deletions src/main/scala/beam/agentsim/agents/vehicles/BeamVehicle.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import beam.agentsim.infrastructure.ParkingStall.ChargingType
import beam.router.Modes
import beam.router.model.BeamLeg
import beam.sim.BeamServices
import beam.sim.common.GeoUtils
import beam.sim.common.GeoUtils.{Straight, TurningDirection}
import com.typesafe.scalalogging.StrictLogging
import org.matsim.api.core.v01.network.{Link, Network}
import org.matsim.api.core.v01.{Coord, Id}
Expand Down Expand Up @@ -186,60 +188,10 @@ object BeamVehicle {
linkArrivalTime: Long,
vehicleId: String,
vehicleType: BeamVehicleType,
turnAtLinkEnd: String,
turnAtLinkEnd: TurningDirection,
numberOfStops: Int
)

/**
* Get the desired direction to be taken , based on the angle between the coordinates
* @param source source coordinates
* @param destination destination coordinates
* @return Direction to be taken ( L / SL / HL / R / HR / SR / S)
*/
def getDirection(source: Coord, destination: Coord): String = {
val radians = computeAngle(source, destination)
radians match {
case _ if radians < 0.174533 || radians >= 6.10865 => "S" // Straight
case _ if radians >= 0.174533 & radians < 1.39626 => "SL" // Soft Left
case _ if radians >= 1.39626 & radians < 1.74533 => "L" // Left
case _ if radians >= 1.74533 & radians < 3.14159 => "HL" // Hard Left
case _ if radians >= 3.14159 & radians < 4.53785 => "HR" // Hard Right
case _ if radians >= 4.53785 & radians < 4.88692 => "R" // Right
case _ if radians >= 4.88692 & radians < 6.10865 => "SR" // Soft Right
case _ => "S" // default => Straight
}
}

/**
* Generate the vector coordinates from the link nodes
* @param link link in the network
* @return vector coordinates
*/
def vectorFromLink(link: Link): Coord = {
new Coord(
link.getToNode.getCoord.getX - link.getFromNode.getCoord.getX,
link.getToNode.getCoord.getY - link.getFromNode.getCoord.getY
)
}

/**
* Computes the angle between two coordinates
* @param source source coordinates
* @param destination destination coordinates
* @return angle between the coordinates (in radians).
*/
def computeAngle(source: Coord, destination: Coord): Double = {
val rad = Math.atan2(
source.getX * destination.getY - source.getY * destination.getX,
source.getX * destination.getX - source.getY * destination.getY
)
if (rad < 0) {
rad + 3.141593 * 2.0
} else {
rad
}
}

/**
* Organizes the fuel consumption data table
* @param beamLeg Instance of beam leg
Expand Down Expand Up @@ -288,9 +240,13 @@ object BeamVehicle {
}
val turnAtLinkEnd = currentLink match {
case Some(curLink) =>
getDirection(vectorFromLink(curLink), vectorFromLink(nextLink.get))
GeoUtils.getDirection(GeoUtils.vectorFromLink(curLink), GeoUtils.vectorFromLink(nextLink.get))
case None =>
"S"
Straight
}
val numStops = turnAtLinkEnd match {
case Straight => 0
case _ => 1
}
FuelConsumptionData(
linkId = id,
Expand All @@ -302,9 +258,7 @@ object BeamVehicle {
vehicleId = id.toString,
vehicleType = vehicleType,
turnAtLinkEnd = turnAtLinkEnd,
numberOfStops =
if (turnAtLinkEnd.equalsIgnoreCase("NA")) 0
else 1
numberOfStops = numStops
)
}.toList
}
Expand Down
66 changes: 34 additions & 32 deletions src/main/scala/beam/analysis/DelayMetricAnalysis.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ import beam.router.Modes.BeamMode.CAR
import beam.sim.BeamServices
import beam.sim.config.BeamConfig
import com.google.inject.Inject
import org.jfree.data.category.{CategoryDataset, DefaultCategoryDataset}
import org.jfree.chart.plot.CategoryPlot
import org.jfree.data.category.DefaultCategoryDataset
import org.matsim.core.api.experimental.events.EventsManager
import org.matsim.core.controler.OutputDirectoryHierarchy
import org.matsim.core.controler.events.IterationEndsEvent

import scala.collection.mutable.Map
import collection.JavaConverters._

case class DelayInLength(delay: Double, length: Int)

Expand All @@ -35,18 +37,17 @@ class DelayMetricAnalysis @Inject()(
private var linkTravelsCount: Map[String, Int] = Map()
private var linkAverageDelay: Map[String, DelayInLength] = Map()

private val bins = Array(0, 100, 250, 500, 1000, 2000, 3000)
private val legends = Array("0-100", "100-250", "250-500", "500-1000", "1000-2000", "2000-3000", "3000+")
private val bins = Array(0, 500, 1000, 2000, 3000)
private val legends = Array("0-500", "500-1000", "1000-2000", "2000-3000", "3000+")
private val capacitiesDelay = scala.collection.mutable.Map[Int, Double]()
val dataset = new DefaultCategoryDataset

private val delayAveragePerKMDataset = new DefaultCategoryDataset
private val delayTotalByLinkCapacityDataset = new DefaultCategoryDataset
private val fileName = "delayTotalByLinkCapacity"
private val xAxisName = "capacity bins"
private val yAxisName = "vehicle delay (hour)"
private val graphTitle = "Delay Metric Analysis"
private val xAxisAverageGraphName = "Iteration(s)"
private val yAxisAverageGraphName = " Average Delay Intensity (sec/km)"
private val averageGraphTitle = "Delay Average per kilometer Analysis"
private val xAxisName = "Iteration (s)"
private val yAxisName = "Total Delay (hour)"
private val graphTitle = "Total Delay by Binned Link Capacity"
private val yAxisAverageGraphName = "Average Delay Intensity (sec/km)"
private val averageGraphTitle = "Average Delay per Kilometer"
var totalTravelTime = 0.0

/**
Expand All @@ -63,7 +64,7 @@ class DelayMetricAnalysis @Inject()(
val linkTravelTimes = pathTraversalEvent.getLinkTravelTimes.split(",").map(_.toInt)
assert(linkIds.length == linkTravelTimes.length)

if (linkIds.length > 0) {
if (linkIds.nonEmpty) {
for (index <- linkIds.indices) {
val linkId = linkIds(index)
val freeLength = networkLinks.get(Id.createLinkId(linkId)).getLength
Expand All @@ -83,10 +84,8 @@ class DelayMetricAnalysis @Inject()(
linkTravelsCount(linkId) = linkTravelsCount.getOrElse(linkId, 0) + 1

linkAverageDelay(linkId) = DelayInLength(
(linkTravelsCount.get(linkId).get * cumulativeDelay.get(linkId).get) / cumulativeLength
.get(linkId)
.get,
linkTravelsCount.get(linkId).get
(linkTravelsCount(linkId) * cumulativeDelay(linkId)) / cumulativeLength(linkId),
linkTravelsCount(linkId)
) //calculate average of link delay for further calculating weighted average

} else if (freeFlowDelay >= -1) {
Expand All @@ -110,22 +109,21 @@ class DelayMetricAnalysis @Inject()(
totalTravelTime = 0
}

def categoryDelayCapacityDataset(): CategoryDataset = {
def categoryDelayCapacityDataset(iteration: Int): Unit = {
cumulativeDelay.keySet foreach { linkId =>
val delay = cumulativeDelay.get(linkId).getOrElse(0.0)
val delay = cumulativeDelay.getOrElse(linkId, 0.0)
val capacity = networkLinks.get(Id.createLinkId(linkId)).getCapacity

val bin = largeset(capacity)
val capacityDelay = capacitiesDelay.get(bin).getOrElse(0.0)
val capacityDelay = capacitiesDelay.getOrElse(bin, 0.0)
capacitiesDelay(bin) = delay + capacityDelay
}

val dataset = new DefaultCategoryDataset
for (index <- bins.indices) {
val bin = bins(index)
val capacityBin: Double = capacitiesDelay.getOrElse(bin, 0)
dataset.addValue(capacityBin / 3600, 0, legends(index))
delayTotalByLinkCapacityDataset.addValue(capacityBin / 3600, legends(index), iteration)
}
dataset
}

// getting the bin for capacity
Expand All @@ -142,29 +140,33 @@ class DelayMetricAnalysis @Inject()(
val avg = linkAverageDelay.values.map(delayInLength => delayInLength.delay).sum / linkAverageDelay.values
.map(delayInLength => delayInLength.length)
.sum
dataset.addValue(avg, 0, iteration)
delayAveragePerKMDataset.addValue(avg, 0, iteration)
}

def generateDelayAnalysis(event: IterationEndsEvent): Unit = {
val dataset = categoryDelayCapacityDataset()
if (dataset != null) {
createDelayCapacityGraph(dataset, event.getIteration, fileName)
categoryDelayCapacityDataset(event.getIteration)
if (delayTotalByLinkCapacityDataset != null) {
createDelayCapacityGraph(fileName)
}
averageDelayDataset(event)
createDelayAveragePerKilometerGraph()
}

def createDelayCapacityGraph(dataset: CategoryDataset, iterationNumber: Int, fileName: String): Unit = {
def createDelayCapacityGraph(fileName: String): Unit = {
val chart = GraphUtils.createStackedBarChartWithDefaultSettings(
dataset,
delayTotalByLinkCapacityDataset,
graphTitle,
xAxisName,
yAxisName,
fileName + ".png",
false
true
)

val plot: CategoryPlot = chart.getCategoryPlot
GraphUtils.plotLegendItems(plot, legends.toList.asJava, delayTotalByLinkCapacityDataset.getRowCount)

val graphImageFile =
GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(iterationNumber, fileName + ".png")
GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputFilename(fileName + ".png")
GraphUtils.saveJFreeChartAsPNG(
chart,
graphImageFile,
Expand All @@ -176,9 +178,9 @@ class DelayMetricAnalysis @Inject()(
def createDelayAveragePerKilometerGraph(): Unit = {
val fileName = controlerIO.getOutputFilename("delayAveragePerKilometer.png")
val chart = GraphUtils.createStackedBarChartWithDefaultSettings(
dataset,
delayAveragePerKMDataset,
averageGraphTitle,
xAxisAverageGraphName,
xAxisName,
yAxisAverageGraphName,
fileName,
false
Expand Down
Loading