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

Emissions feature - addind missing activities #3907

Draft
wants to merge 1 commit into
base: develop
Choose a base branch
from
Draft
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 @@ -343,6 +343,18 @@ trait DrivesVehicle[T <: DrivingData] extends BeamAgent[T] with Stash with Expon
}
}

val initialIdleActivity = BeamVehicle.getInitialIDLEActivityForEmissions(
tick,
currentLeg.travelPath.linkIds.headOption.getOrElse(Int.MinValue),
currentBeamVehicle,
beamServices
)
val maybeInitialIdleEmission = currentBeamVehicle.emitEmissions(
initialIdleActivity,
classOf[VehicleEntersTrafficEvent],
beamServices
)

val vehicleActivityDataFixed = BeamVehicle.addFirstLinkActivityForEmissions(
currentLeg.startTime,
vehicleActivityData,
Expand Down Expand Up @@ -373,9 +385,12 @@ trait DrivesVehicle[T <: DrivingData] extends BeamAgent[T] with Stash with Expon
classOf[PathTraversalEvent],
beamServices
)
val emissionsProfile = EmissionsProfile.join(emissionsProfilePTE, emissionsProfileIDLE)
val emissionsProfile = EmissionsProfile.join(
emissionsProfilePTE,
EmissionsProfile.join(emissionsProfileIDLE, maybeInitialIdleEmission)
)

val numberOfPassengers: Int = calculateNumberOfPassengersBasedOnCurrentTripMode(data, currentLeg, riders)
val currentTourMode: Option[String] = getCurrentTripMode(data)
val pte = PathTraversalEvent(
tick,
currentVehicleUnderControl,
Expand Down Expand Up @@ -628,7 +643,6 @@ trait DrivesVehicle[T <: DrivingData] extends BeamAgent[T] with Stash with Expon
tollsAccumulated += tollOnCurrentLeg
val numberOfPassengers: Int =
calculateNumberOfPassengersBasedOnCurrentTripMode(data, partiallyCompletedBeamLeg, riders)
val currentTourMode: Option[String] = getCurrentTripMode(data)
val pte = PathTraversalEvent(
updatedStopTick,
currentVehicleUnderControl,
Expand Down
30 changes: 23 additions & 7 deletions src/main/scala/beam/agentsim/agents/ridehail/RideHailAgent.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ import beam.utils.NetworkHelper
import beam.utils.logging.LogActorState
import beam.utils.reflection.ReflectionUtils
import com.conveyal.r5.transit.TransportNetwork
import org.matsim.api.core.v01.events.PersonEntersVehicleEvent
import org.matsim.api.core.v01.events.{PersonEntersVehicleEvent, VehicleEntersTrafficEvent}
import org.matsim.api.core.v01.{Coord, Id}
import org.matsim.core.api.experimental.events.EventsManager
import org.matsim.core.network.NetworkUtils
import org.matsim.core.utils.misc.Time
import org.matsim.vehicles.Vehicle

Expand Down Expand Up @@ -496,19 +497,34 @@ class RideHailAgent(
needsToEndShift = false
isCurrentlyOnShift = false
}
updateLatestObservedTick(tick)
currentBeamVehicle.setLastVehicleTime(Some(tick))
eventsManager.processEvent(new ShiftEvent(tick, StartShift, id.toString, vehicle))
log.debug("state(RideHailingAgent.Offline): starting shift {}", id)
holdTickAndTriggerId(tick, triggerId)
isStartingNewShift = true

val newLocation = data.remainingShifts.headOption match {
case Some(Shift(_, Some(startLocation))) =>
//TODO this is teleportation and should be fixed in favor of new protocol to make vehicles move
SpaceTime(startLocation, time = tick)
case _ =>
vehicle.spaceTime.copy(time = tick)
}
val linkId = NetworkUtils.getNearestLink(beamServices.beamScenario.network, newLocation.loc).getId
val initialIdleActivity = BeamVehicle.getInitialIDLEActivityForEmissions(
tick,
linkId.toString.toInt,
currentBeamVehicle,
beamServices
)
val maybeInitialIdleEmission = currentBeamVehicle.emitEmissions(
initialIdleActivity,
classOf[VehicleEntersTrafficEvent],
beamServices
)

updateLatestObservedTick(tick)
currentBeamVehicle.setLastVehicleTime(Some(tick))
eventsManager.processEvent(new ShiftEvent(tick, StartShift, id.toString, vehicle, maybeInitialIdleEmission))
log.debug("state(RideHailingAgent.Offline): starting shift {}", id)
holdTickAndTriggerId(tick, triggerId)
isStartingNewShift = true

if (debugEnabled) outgoingMessages += ev
if (debugEnabled)
outgoingMessages += NotifyVehicleIdle(
Expand Down
38 changes: 37 additions & 1 deletion src/main/scala/beam/agentsim/agents/vehicles/BeamVehicle.scala
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,7 @@ object BeamVehicle {
}

/*
To fix emissions calculations:
For emissions calculations:
- for possible IDLE vehicle time between shift start event and PathTraversal event
- for possible IDLE vehicle time between driver enters vehicle and PathTraversal event
*/
Expand Down Expand Up @@ -835,4 +835,40 @@ object BeamVehicle {
}
}

/*
For emissions calculations:
- for IDLE vehicle time before any other activity
*/
def getInitialIDLEActivityForEmissions(
tick: Int,
linkId: Int,
beamVehicle: BeamVehicle,
beamServices: BeamServices
): IndexedSeq[BeamVehicle.VehicleActivityData] = {
(beamVehicle.lastLinkVisited, beamVehicle.lastIDLEStartTime) match {
case (Some(_), _) => IndexedSeq.empty[BeamVehicle.VehicleActivityData]
case (_, Some(_)) => IndexedSeq.empty[BeamVehicle.VehicleActivityData]
case _ =>
val currentLink: Option[Link] = beamServices.networkHelper.getLink(linkId)
val totalDurationSeconds = tick.toDouble
val startTimeToDurationPairs = startTimeAndDurationToMultipleIntervals(0, totalDurationSeconds)
val vads = startTimeToDurationPairs.map { case (startTime, duration) =>
VehicleActivityData(
time = startTime,
linkId = linkId,
vehicleType = beamVehicle.beamVehicleType,
payloadInKg = None,
linkNumberOfLanes = currentLink.map(_.getNumberOfLanes().toInt),
linkLength = currentLink.map(_.getLength),
averageSpeed = None,
taz = currentLink.flatMap(link => beamServices.beamScenario.tazTreeMap.getTAZfromLink(link.getId)),
parkingDuration = Some(duration),
parkingType = Some(ParkingType.Public),
activityType = Some(ParkingActivityType.IDLE.toString),
linkTravelTime = None
)
}
vads.toIndexedSeq
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import com.typesafe.scalalogging.LazyLogging
import com.univocity.parsers.common.record.Record
import com.univocity.parsers.csv.{CsvParser, CsvParserSettings}
import org.matsim.api.core.v01.Id
import org.matsim.api.core.v01.events.VehicleEntersTrafficEvent
import org.matsim.core.utils.io.IOUtils
import org.slf4j.LoggerFactory

Expand Down Expand Up @@ -267,8 +268,7 @@ object VehicleEmissions extends LazyLogging {

val emissionProcesses = {
EmissionsProfile.values.flatMap {
// IDLE activity should be the first element of VehicleActivity data sequence
// the type is PathTraversalEvent because there is no difference, IDLE activity happens between other events
// the type is PathTraversalEvent because the vehicle used to be moving, IDLE activity happens between other events
case process @ IDLEX if vehicleActivity == classOf[PathTraversalEvent] && averageSpeed == 0 =>
Some(process)
case process @ (RUNEX | PMBW | PMTW | RUNLOSS)
Expand All @@ -283,6 +283,10 @@ object VehicleEmissions extends LazyLogging {
Some(process)
case process @ (STREX | DIURN | HOTSOAK | RUNLOSS) if vehicleActivity == classOf[LeavingParkingEvent] =>
Some(process)
case process @ DIURN if vehicleActivity == classOf[VehicleEntersTrafficEvent] =>
Some(process)
// TODO add a case for DIURN to emit it for the rest of simulation time after last vehicle activity
// TODO add a case for HOTSOAK to emit it once after vehicle did its last activity
case _ => None
}
}
Expand Down Expand Up @@ -358,8 +362,8 @@ object VehicleEmissions extends LazyLogging {
* @return Total emissions in grams
*/
RUNEX -> { (ratesBySpeedBin: Emissions, data: BeamVehicle.VehicleActivityData) =>
val vehicleMilesTraveledInMiles = data.linkLength.map(_ / 1609.344).getOrElse(0.0)
ratesBySpeedBin * vehicleMilesTraveledInMiles
val vehicleTraveledInMiles = data.linkLength.map(_ / 1609.344).getOrElse(0.0)
ratesBySpeedBin * vehicleTraveledInMiles
},
/**
* Calculate Idle Exhaust Emissions (IDLEX)
Expand All @@ -368,6 +372,7 @@ object VehicleEmissions extends LazyLogging {
* rates Emission rate (grams per vehicle-idle hour)
* @return Total emissions in grams
*/
// FIXME not all vehicles are running engine while parked
IDLEX -> { (rates: Emissions, data: BeamVehicle.VehicleActivityData) =>
val vehicleIdleInHours = data.parkingDuration.map(_ / 3600.0).getOrElse(0.0)
rates * vehicleIdleInHours
Expand All @@ -391,6 +396,7 @@ object VehicleEmissions extends LazyLogging {
* rates Emission rate (grams per vehicle-hour)
* @return Total emissions in grams
*/
// FIXME we need to emit this for all hours before vehicle activity and for the rest of simulation hours after vehicle stop being active
// FIXME we might underestimate DIURN: Ridehail vehicles do not park, they idle or stop engine while waiting
DIURN -> { (rates: Emissions, data: BeamVehicle.VehicleActivityData) =>
val vehicleParkingInHours = data.parkingDuration.map(_ / 3600.0).getOrElse(0.0)
Expand All @@ -415,6 +421,7 @@ object VehicleEmissions extends LazyLogging {
* rates Emission rate (grams per vehicle-hour)
* @return Total emissions in grams
*/
// FIXME using parkingDuration here might be incorrect!
RUNLOSS -> { (rates: Emissions, data: BeamVehicle.VehicleActivityData) =>
val vehicleHoursTraveledInHours =
data.linkTravelTime.map(_ / 3600.0).orElse(data.parkingDuration.map(_ / 3600.0)).getOrElse(0.0)
Expand Down
2 changes: 1 addition & 1 deletion src/test/scala/beam/agentsim/agents/EmissionsSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ class EmissionsSpec extends AnyFunSpecLike with Matchers with BeamHelper with Be
}

val outPath = runWithConfig(
"test/input/beamville/beam-urbansimv2-emissions.conf",
"test/input/beamville/beam-urbansimv2-emissions-rh.conf",
{
case sh: ShiftEvent if sh.shiftEventType == StartShift => lastVehicleShiftEvent(sh.vehicle.id.toString) = sh
case e: PathTraversalEvent if e.vehicleType == "RH_Car" && e.emissionsProfile.isDefined =>
Expand Down
Loading