From b6efe1af95bd733f2d48ac1911cf21eac2938816 Mon Sep 17 00:00:00 2001 From: Dmitry Openkov Date: Mon, 21 Mar 2022 20:23:08 +0300 Subject: [PATCH 01/25] Removed collapsing parking zones on the link level because parking zone contains the real parking zone id now. Fixed small defects. --- .../agents/vehicles/VehicleManager.scala | 8 + .../HierarchicalParkingManager.scala | 178 +++++++++--------- .../ParkingManagerBenchmark.scala | 56 ++++-- .../parking/ParkingZoneFileUtils.scala | 58 +++++- src/main/scala/beam/utils/MathUtils.scala | 2 + .../ChargingNetworkManagerSpec.scala | 3 +- .../HierarchicalParkingManagerSpec.scala | 4 +- .../HierarchicalParkingManagerUtilSpec.scala | 49 ++--- .../ParallelParkingManagerSpec.scala | 22 +-- .../ZonalParkingManagerSpec.scala | 18 +- .../parking/ParkingZoneFileUtilsSpec.scala | 36 ++-- test/input/sf-light/link-parking.csv | 3 - test/input/sf-light/link-parking.csv.gz | 4 +- ...t-1k-csv-linkparking-pickups-dropoffs.conf | 4 +- .../sf-light/sf-light-25k-experiment-2.conf | 2 +- .../sf-light/sf-light-25k-experiment-3.conf | 2 +- .../sf-light/sf-light-25k-experiment-4.conf | 2 +- .../sf-light/sf-light-25k-experiment-5.conf | 2 +- 18 files changed, 259 insertions(+), 194 deletions(-) delete mode 100644 test/input/sf-light/link-parking.csv diff --git a/src/main/scala/beam/agentsim/agents/vehicles/VehicleManager.scala b/src/main/scala/beam/agentsim/agents/vehicles/VehicleManager.scala index 667a94ef1f2..a39654ee7cf 100644 --- a/src/main/scala/beam/agentsim/agents/vehicles/VehicleManager.scala +++ b/src/main/scala/beam/agentsim/agents/vehicles/VehicleManager.scala @@ -79,4 +79,12 @@ object VehicleManager extends LazyLogging { } reservedForMaybe map { case ReservedFor(mngId, mngType) => createOrGetReservedFor(mngId.toString, mngType) } } + + def reserveForToString(reservedFor: ReservedFor): String = { + reservedFor match { + case NoManager => "None" + case AnyManager => "Any" + case x => x.toString + } + } } diff --git a/src/main/scala/beam/agentsim/infrastructure/HierarchicalParkingManager.scala b/src/main/scala/beam/agentsim/infrastructure/HierarchicalParkingManager.scala index 4926515fe73..298fd0de1fd 100644 --- a/src/main/scala/beam/agentsim/infrastructure/HierarchicalParkingManager.scala +++ b/src/main/scala/beam/agentsim/infrastructure/HierarchicalParkingManager.scala @@ -40,14 +40,14 @@ class HierarchicalParkingManager( checkThatNumberOfStallsMatch: Boolean = false ) extends ParkingNetwork[Link](parkingZones) { - protected val actualLinkParkingZones: Map[Id[ParkingZoneId], ParkingZone[Link]] = - HierarchicalParkingManager.collapse(parkingZones) - + /** + * Contains quad tree of links for each TAZ + */ protected val tazLinks: Map[Id[TAZ], QuadTree[Link]] = createTazLinkQuadTreeMapping(linkToTAZMapping) protected val (tazParkingZones, linkZoneToTazZoneMap) = convertToTazParkingZones( - actualLinkParkingZones, + parkingZones, linkToTAZMapping.map { case (link, taz) => link.getId -> taz.tazId } @@ -82,11 +82,17 @@ class HierarchicalParkingManager( UbiqiutousParkingAvailability ) - protected val linkZoneSearchMap: Map[Id[Link], Map[ParkingZoneDescription, ParkingZone[Link]]] = - createLinkZoneSearchMap(actualLinkParkingZones) + /** + * each link is mapped to a Map: parking zone description -> list of parking zones with these params + */ + protected val linkZoneSearchMap: Map[Id[Link], Map[ParkingZoneDescription, IndexedSeq[ParkingZone[Link]]]] = + createLinkZoneSearchMap(parkingZones) if (checkThatNumberOfStallsMatch) { - stallsInfo() + val wrongTaz = wrongNumStallTazCollection() + if (wrongTaz.nonEmpty) { + logger.warn(s"Number of non matched stalls on TAZ and link level: ${wrongTaz.size}") + } } /** @@ -100,47 +106,15 @@ class HierarchicalParkingManager( ): Option[ParkingInquiryResponse] = { logger.debug("Received parking inquiry: {}", inquiry) + //searchForParkingStall always returns a ParkingZoneSearchResult. It may contain either a real parkingStall + // (success) or emergency parking stall (not found an appropriate one) val Some(ParkingZoneSearch.ParkingZoneSearchResult(tazParkingStall, tazParkingZone, _, _, _)) = tazSearchFunctions.searchForParkingStall(inquiry) val (parkingStall: ParkingStall, parkingZone: ParkingZone[Link]) = - tazLinks.get(tazParkingZone.geoId.asInstanceOf[Id[TAZ]]) match { + tazLinks.get(tazParkingZone.geoId) match { case Some(linkQuadTree) => - val foundZoneDescription = ParkingZoneDescription.describeParkingZone(tazParkingZone) - val startingPoint = - linkQuadTree.getClosest(inquiry.destinationUtm.loc.getX, inquiry.destinationUtm.loc.getY).getCoord - TAZTreeMap.ringSearch( - linkQuadTree, - startingPoint, - minSearchRadius / 4, - maxSearchRadius * 5, - radiusMultiplication = 1.5 - ) { link => - for { - linkZones <- linkZoneSearchMap.get(link.getId) - zone <- linkZones.get(foundZoneDescription) if zone.stallsAvailable > 0 - } yield { - (tazParkingStall.copy(zone.geoId, parkingZoneId = zone.parkingZoneId, locationUTM = link.getCoord), zone) - } - } match { - case Some(foundResult) => foundResult - case None => //Cannot find required links within the TAZ, this means the links is too far from the starting point - logger.warn( - "Cannot find link parking stall for taz id {}, foundZoneDescription = {}", - tazParkingZone.geoId, - foundZoneDescription - ) - import scala.collection.JavaConverters._ - val tazLinkZones = for { - link <- linkQuadTree.values().asScala.toList - linkZones <- linkZoneSearchMap.get(link.getId) - zone <- linkZones.get(foundZoneDescription) if zone.stallsAvailable > 0 - } yield { - zone - } - logger.warn("Actually tazLink zones {}", tazLinkZones) - lastResortStallAndZone(inquiry.destinationUtm.loc) - } + findAppropriateLinkParkingStallWithinTaz(inquiry, tazParkingZone, linkQuadTree, tazParkingStall) case None => //no corresponding links, this means it's a special zone tazParkingStall.geoId match { case TAZ.DefaultTAZId => @@ -168,6 +142,54 @@ class HierarchicalParkingManager( Some(ParkingInquiryResponse(parkingStall, inquiry.requestId, inquiry.triggerId)) } + private def findAppropriateLinkParkingStallWithinTaz( + inquiry: ParkingInquiry, + tazParkingZone: ParkingZone[TAZ], + linkQuadTree: QuadTree[Link], + tazParkingStall: ParkingStall + ): (ParkingStall, ParkingZone[Link]) = { + val foundZoneDescription = ParkingZoneDescription.describeParkingZone(tazParkingZone) + val startingPoint = + linkQuadTree.getClosest(inquiry.destinationUtm.loc.getX, inquiry.destinationUtm.loc.getY).getCoord + TAZTreeMap.ringSearch( + linkQuadTree, + startingPoint, + minSearchRadius / 4, + maxSearchRadius * 5, + radiusMultiplication = 1.5 + ) { link => + for { + linkZones <- linkZoneSearchMap.get(link.getId) + zoneList <- linkZones.get(foundZoneDescription) + zone <- zoneList.find(_.stallsAvailable > 0) + } yield { + (tazParkingStall.copy(zone.geoId, parkingZoneId = zone.parkingZoneId, locationUTM = link.getCoord), zone) + } + } match { + case Some(foundResult) => foundResult + case None => //Cannot find required links within the TAZ, this means the links is too far from the starting point + logger.warn( + "Cannot find link parking stall for taz id {}, foundZoneDescription = {}, you could increase maxSearchRadius", + tazParkingZone.geoId, + foundZoneDescription + ) + import scala.collection.JavaConverters._ + val appropriateLinkZones = for { + link <- linkQuadTree.values().asScala.toList + linkZones <- linkZoneSearchMap.get(link.getId) + zoneList <- linkZones.get(foundZoneDescription) + zone <- zoneList.find(_.stallsAvailable > 0) + } yield { + zone -> link + } + logger.warn("Link zones {}", appropriateLinkZones) + val maybeAppropriateResult = appropriateLinkZones.headOption.map { case (zone, link) => + (tazParkingStall.copy(zone.geoId, parkingZoneId = zone.parkingZoneId, locationUTM = link.getCoord), zone) + } + maybeAppropriateResult.getOrElse(lastResortStallAndZone(inquiry.destinationUtm.loc)) + } + } + /** * @param release ReleaseParkingStall * @return @@ -178,11 +200,11 @@ class HierarchicalParkingManager( // this is an infinitely available resource; no update required logger.debug("Releasing a stall in the default/emergency zone") true - } else if (!actualLinkParkingZones.contains(parkingZoneId)) { + } else if (!parkingZones.contains(parkingZoneId)) { logger.debug("Attempting to release stall in zone {} which is an illegal parking zone id", parkingZoneId) false } else { - val linkZone = actualLinkParkingZones(parkingZoneId) + val linkZone = parkingZones(parkingZoneId) val tazZoneId = linkZoneToTazZoneMap(parkingZoneId) val tazZone = tazParkingZones(tazZoneId) ParkingZone.releaseStall(linkZone) @@ -194,9 +216,9 @@ class HierarchicalParkingManager( * This method can be used for validating that stallsAvailable is the same for each TAZ and sum of all the links that * belongs to this TAZ */ - private def stallsInfo(): Unit = { - val notMatchedTazIds = tazMap.getTAZs - .map { taz => + private def wrongNumStallTazCollection(): Iterable[Id[TAZ]] = { + tazMap.getTAZs + .flatMap { taz => val linkStalls = tazLinks .get(taz.tazId) .map { linkTree => @@ -204,8 +226,9 @@ class HierarchicalParkingManager( val links = linkTree.values().asScala links.flatMap { link => for { - map <- linkZoneSearchMap.get(link.getId).toIterable - zone <- map.values + map <- linkZoneSearchMap.get(link.getId).toIterable + zoneList <- map.values + zone <- zoneList } yield zone.stallsAvailable.toLong }.sum } @@ -217,9 +240,6 @@ class HierarchicalParkingManager( } yield tazParkingZones(zoneId).stallsAvailable.toLong).sum if (tazStalls != linkStalls) Some(taz.tazId) else None } - val notMatch = notMatchedTazIds.count(_.nonEmpty) - if (notMatch == 0) logger.info(s"Number of non matched stalls on TAZ and link level: $notMatch") - else logger.warn(s"Number of non matched stalls on TAZ and link level: $notMatch") } private def lastResortStallAndZone(location: Location) = { @@ -340,10 +360,10 @@ object HierarchicalParkingManager { } } //generate taz parking zones - val tazZones = tazZoneDescriptions.zipWithIndex.map { case ((tazId, description, linkZones), _) => + val tazZones = tazZoneDescriptions.zipWithIndex.map { case ((tazId, description, linkZones), id) => val numStalls = Math.min(linkZones.map(_.maxStalls.toLong).sum, Int.MaxValue).toInt val parkingZone = ParkingZone.init[TAZ]( - None, + Some(Id.create(id, classOf[ParkingZoneId])), geoId = tazId, parkingType = description.parkingType, maxStalls = numStalls, @@ -353,23 +373,24 @@ object HierarchicalParkingManager { timeRestrictions = description.timeRestrictions ) parkingZone.parkingZoneId -> parkingZone - }.toMap + } //link zone to taz zone map - val linkZoneToTazZoneMap = tazZones - .zip(tazZoneDescriptions.map { case (_, _, linkZones) => linkZones }) - .flatMap { case ((parkingZoneId, _), linkZones) => linkZones.map(_.parkingZoneId -> parkingZoneId) } - (tazZones, linkZoneToTazZoneMap) + val tazZonesAndLinkZones = tazZones.zip(tazZoneDescriptions.map { case (_, _, linkZones) => linkZones }) + val linkZoneToTazZoneMap = tazZonesAndLinkZones + .flatMap { case ((tazParkingZoneId, _), linkZones) => linkZones.map(_.parkingZoneId -> tazParkingZoneId) } + (tazZones.toMap, linkZoneToTazZoneMap.toMap) } private def createLinkZoneSearchMap( parkingZones: Map[Id[ParkingZoneId], ParkingZone[Link]] - ): Map[Id[Link], Map[ParkingZoneDescription, ParkingZone[Link]]] = { - parkingZones.foldLeft(Map.empty: Map[Id[Link], Map[ParkingZoneDescription, ParkingZone[Link]]]) { + ): Map[Id[Link], Map[ParkingZoneDescription, IndexedSeq[ParkingZone[Link]]]] = { + parkingZones.foldLeft(Map.empty: Map[Id[Link], Map[ParkingZoneDescription, IndexedSeq[ParkingZone[Link]]]]) { case (accumulator, (_, zone)) => val zoneDescription = ParkingZoneDescription.describeParkingZone(zone) val parking = accumulator.getOrElse(zone.geoId, Map()) - accumulator.updated(zone.geoId, parking.updated(zoneDescription, zone)) + val zoneList = parking.getOrElse(zoneDescription, IndexedSeq.empty) + accumulator.updated(zone.geoId, parking.updated(zoneDescription, zoneList :+ zone)) } } @@ -383,35 +404,4 @@ object HierarchicalParkingManager { private def invertMap(linkToTAZMapping: Map[Link, TAZ]): Map[TAZ, Set[Link]] = { linkToTAZMapping.groupBy(_._2).mapValues(_.keys.toSet) } - - /** - * Collapses multiple similar parking zones in the same Link to a single zone - * @param parkingZones the parking zones - * @return collapsed parking zones - */ - def collapse(parkingZones: Map[Id[ParkingZoneId], ParkingZone[Link]]): Map[Id[ParkingZoneId], ParkingZone[Link]] = - parkingZones - .groupBy(_._2.geoId) - .flatMap { case (linkId, zones) => - zones.values - .groupBy(ParkingZoneDescription.describeParkingZone) - .map { case (descr, linkZones) => (linkId, descr, linkZones.map(_.maxStalls.toLong).sum) } - } - .filter { case (_, _, maxStalls) => maxStalls > 0 } - .zipWithIndex - .map { case ((linkId, description, maxStalls), id) => - val numStalls = Math.min(maxStalls, Int.MaxValue).toInt - val parkingZone = ParkingZone.init[Link]( - None, - geoId = linkId, - parkingType = description.parkingType, - maxStalls = numStalls, - reservedFor = description.reservedFor, - chargingPointType = description.chargingPointType, - pricingModel = description.pricingModel, - timeRestrictions = description.timeRestrictions - ) - parkingZone.parkingZoneId -> parkingZone - } - .toMap } diff --git a/src/main/scala/beam/agentsim/infrastructure/ParkingManagerBenchmark.scala b/src/main/scala/beam/agentsim/infrastructure/ParkingManagerBenchmark.scala index f63247977d7..eb20f701ff3 100644 --- a/src/main/scala/beam/agentsim/infrastructure/ParkingManagerBenchmark.scala +++ b/src/main/scala/beam/agentsim/infrastructure/ParkingManagerBenchmark.scala @@ -59,25 +59,25 @@ class ParkingManagerBenchmark( object ParkingManagerBenchmark extends StrictLogging { -// val pathToPlans: String = "D:/Work/beam/ParallelJDEQSim/sfbay-smart-base/0.plans.xml.gz" - val pathToPlans: String = "https://beam-outputs.s3.us-east-2.amazonaws.com/parallel_parking_manager/0.plans.xml.gz" + val pathToPlans: String = "data_files/sfbay-smartbaseline/0.plans.xml.gz" +// val pathToPlans: String = "https://beam-outputs.s3.us-east-2.amazonaws.com/parallel_parking_manager/0.plans.xml.gz" -// val pathToTazParking: String = "D:/Work/beam/ParallelJDEQSim/sfbay-smart-base/parking/taz-parking-unlimited-fast-limited-l2-150-baseline.csv" - val pathToTazParking: String = - "https://beam-outputs.s3.us-east-2.amazonaws.com/parallel_parking_manager/taz-parking-unlimited-fast-limited-l2-150-baseline.csv.gz" + val pathToTazParking: String = "production/sfbay/parking/init1-7_2022_Feb_03_wgs84_withFees_cleaned.csv" +// val pathToTazParking: String = +// "https://beam-outputs.s3.us-east-2.amazonaws.com/parallel_parking_manager/taz-parking-unlimited-fast-limited-l2-150-baseline.csv.gz" -// val pathToLinkParking: String = "D:/Work/beam/ParallelJDEQSim/sfbay-smart-base/parking/link-parking-unlimited-fast-limited-l2-150-baseline.csv" - val pathToLinkParking: String = - "https://beam-outputs.s3.us-east-2.amazonaws.com/parallel_parking_manager/link-parking-unlimited-fast-limited-l2-150-baseline.csv.gz" + val pathToLinkParking: String = "data_files/sfbay-smartbaseline/link-parking.csv" +// val pathToLinkParking: String = +// "https://beam-outputs.s3.us-east-2.amazonaws.com/parallel_parking_manager/link-parking-unlimited-fast-limited-l2-150-baseline.csv.gz" -// val pathToTAZ: String = "D:/Work/beam/ParallelJDEQSim/sfbay-smart-base/taz-centers.csv" - val pathToTAZ: String = "https://beam-outputs.s3.us-east-2.amazonaws.com/parallel_parking_manager/taz-centers.csv.gz" + val pathToTAZ: String = "production/sfbay/taz-centers.csv" +// val pathToTAZ: String = "https://beam-outputs.s3.us-east-2.amazonaws.com/parallel_parking_manager/taz-centers.csv.gz" -// val pathToNetwork: String = "D:/Work/beam/ParallelJDEQSim/sfbay-smart-base/outputNetwork.xml.gz" - val pathToNetwork: String = - "https://beam-outputs.s3.us-east-2.amazonaws.com/parallel_parking_manager/outputNetwork.xml.gz" + val pathToNetwork: String = "production/sfbay/r5-simple-no-local/physsim-network.xml" +// val pathToNetwork: String = +// "https://beam-outputs.s3.us-east-2.amazonaws.com/parallel_parking_manager/outputNetwork.xml.gz" - val parkingStallCountScalingFactor: Double = 0.13 + val parkingStallCountScalingFactor: Double = 1.0 val parkingCostScalingFactor: Double = 1.0 val typeSafeConfig: Config = ConfigFactory @@ -109,7 +109,7 @@ object ParkingManagerBenchmark extends StrictLogging { val seed: Int = 42 val nTimes: Int = 1 - val fractionToBench: Double = 0.3 + val fractionToBench: Double = 0.5 def main(args: Array[String]): Unit = { implicit val ec: ExecutionContext = scala.concurrent.ExecutionContext.Implicits.global @@ -230,6 +230,28 @@ object ParkingManagerBenchmark extends StrictLogging { checkThatNumberOfStallsMatch = true ) parkingNetwork + case "hierarchical-taz" => + val linkQuadTree: QuadTree[Link] = + LinkLevelOperations.getLinkTreeMap(network.getLinks.values().asScala.toSeq) + val linkToTAZMapping: Map[Link, TAZ] = LinkLevelOperations.getLinkToTazMapping(network, tazTreeMap) + val (tazZones: Map[Id[ParkingZoneId], ParkingZone[TAZ]], _) = + loadZones(tazTreeMap.tazQuadTree, pathToTazParking, beamConfig) + val linkParkingZones: Map[Id[ParkingZoneId], ParkingZone[Link]] = ParkingZoneFileUtils + .generateLinkParkingOutOfTazParking(tazZones, linkQuadTree, linkToTAZMapping, tazTreeMap) +// ParkingZoneFileUtils.toCsv(linkParkingZones, "production/sfbay/parking/init1-7_2022_Feb_03_wgs84_withFees_link.csv") + val parkingNetwork = HierarchicalParkingManager.init( + linkParkingZones, + tazTreeMap, + linkToTAZMapping, + geoUtils.distUTMInMeters, + beamConfig.beam.agentsim.agents.parking.minSearchRadius, + beamConfig.beam.agentsim.agents.parking.maxSearchRadius, + boundingBox, + seed, + beamConfig.beam.agentsim.agents.parking.mulitnomialLogit, + checkThatNumberOfStallsMatch = true + ) + parkingNetwork } val bench = new ParkingManagerBenchmark(activityLocations, parkingNetwork) @@ -267,7 +289,7 @@ object ParkingManagerBenchmark extends StrictLogging { }) logger.info("activities written") - val (result, responses) = benchmark("parallel", nTimes, parkingLocations) + val (result, responses) = benchmark("hierarchical-taz", nTimes, parkingLocations) val (zonalResult, zonalResponses) = benchmark("zonal", nTimes, parkingLocations) logger.info("#####################################################################") @@ -275,7 +297,7 @@ object ParkingManagerBenchmark extends StrictLogging { logger.info(zonalResult) logger.info("#####################################################################") - writeToCsv(responses, "./par_parking.csv") + writeToCsv(responses, "./hir_parking.csv") writeToCsv(zonalResponses, "./zonal_parking.csv") analyzeResult(responses.head.groupBy(_.stall.tazId), zonalResponses.head.groupBy(_.stall.tazId)) diff --git a/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZoneFileUtils.scala b/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZoneFileUtils.scala index 6acd6087742..836e2d04381 100644 --- a/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZoneFileUtils.scala +++ b/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZoneFileUtils.scala @@ -5,6 +5,7 @@ import beam.agentsim.agents.vehicles.VehicleManager.ReservedFor import beam.agentsim.agents.vehicles.{VehicleCategory, VehicleManager} import beam.agentsim.infrastructure.charging.ChargingPointType import beam.agentsim.infrastructure.parking.ParkingZoneSearch.ZoneSearchTree +import beam.agentsim.infrastructure.taz.{TAZ, TAZTreeMap} import beam.sim.BeamServices import beam.sim.config.BeamConfig import beam.utils.csv.GenericCsvReader @@ -14,8 +15,12 @@ import org.matsim.api.core.v01.{Coord, Id} import org.matsim.core.network.NetworkUtils import org.matsim.core.utils.io.IOUtils import org.apache.commons.lang3.StringUtils.isBlank +import org.matsim.api.core.v01.network.Link +import org.matsim.core.utils.collections.QuadTree import java.io.{BufferedReader, File, IOException} +import java.text.{DecimalFormat, DecimalFormatSymbols} +import java.util.Locale import scala.annotation.tailrec import scala.collection.mutable import scala.util.{Failure, Random, Success, Try} @@ -278,6 +283,7 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { val csvRow = iterator.next() val updatedAccumulator = parseParkingZoneFromRow( csvRow, + accumulator.totalRows, rand, beamConfig, beamServices, @@ -329,6 +335,7 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { Try { parseParkingZoneFromRow( csvRow, + accumulator.totalRows, random, beamConfig, beamServices, @@ -445,6 +452,7 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { */ def parseParkingZoneFromRow[GEO: GeoLevel]( csvRow: jMap, + rowNumber: Int, rand: Random, beamConfig: Option[BeamConfig], beamServices: Option[BeamServices], @@ -480,7 +488,8 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { val chargingPoint = ChargingPointType(chargingTypeString) val numStalls = calculateNumStalls(numStallsString.toDouble, reservedFor, parkingStallCountScalingFactor) val parkingZoneIdMaybe = - if (parkingZoneIdString == null || parkingZoneIdString.isEmpty) None + if (parkingZoneIdString == null || parkingZoneIdString.isEmpty) + Some(ParkingZone.createId(rowNumber.toString)) else Some(ParkingZone.createId(parkingZoneIdString)) val linkMaybe = (!isBlank(locationXString) && !isBlank(locationYString)) match { case true if beamServices.isDefined => @@ -592,6 +601,38 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { ParkingLoadingAccumulator(accumulator.zones, accumulator.tree, accumulator.totalRows + 1, accumulator.failedRows) } + def generateLinkParkingOutOfTazParking( + tazZones: Map[Id[ParkingZoneId], ParkingZone[TAZ]], + linkQuadTree: QuadTree[Link], + linkToTAZMapping: Map[Link, TAZ], + tazTreeMap: TAZTreeMap + ): Map[Id[ParkingZoneId], ParkingZone[Link]] = { + val tazToLinksMapping = linkToTAZMapping.groupBy { case (_, taz) => taz.tazId }.mapValues(_.keys.toIndexedSeq) + val random = new Random() + tazZones.mapValues { zone => + val links = tazToLinksMapping.getOrElse( + zone.geoId, { + val taz = tazTreeMap.getTAZ(zone.geoId).get + val link = linkQuadTree.getClosest(taz.coord.getX, taz.coord.getY) + IndexedSeq(link) + } + ) + val link = zone.link.getOrElse(MathUtils.selectRandomElement(links, random)) + new ParkingZone[Link]( + zone.parkingZoneId, + link.getId, + zone.parkingType, + zone.stallsAvailable, + zone.maxStalls, + zone.reservedFor, + zone.chargingPointType, + zone.pricingModel, + zone.timeRestrictions, + Some(link) + ) + } + } + /** * generates ubiquitous parking from a taz centers file, such as test/input/beamville/taz-centers.csv * @param geoObjects geo objects that should be used to hold parking stalls @@ -672,20 +713,23 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { */ @SuppressWarnings(Array("UnusedMethodParameter")) // TODO: scapegoat bug? def toCsv[GEO: GeoLevel](parkingZones: Map[Id[ParkingZoneId], ParkingZone[GEO]], filePath: String): Unit = { - val fileContent = parkingZones - .map { case (_, parkingZone) => + val df = new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.ENGLISH)) + df.setMaximumFractionDigits(7) + val fileContent = parkingZones.values.toIndexedSeq + .sortBy(_.parkingZoneId) + .map { parkingZone => List( parkingZone.geoId, parkingZone.parkingType, parkingZone.pricingModel.getOrElse(""), parkingZone.chargingPointType.getOrElse(""), parkingZone.maxStalls, - parkingZone.pricingModel.map(_.costInDollars).getOrElse(""), - parkingZone.reservedFor.toString.mkString("|"), + parkingZone.pricingModel.map(pricing => df.format(pricing.costInDollars * 100)).getOrElse(""), + VehicleManager.reserveForToString(parkingZone.reservedFor), parkingZone.timeRestrictions.map(x => x._1.toString + "|" + x._2.toString).mkString(";"), - parkingZone.toString, parkingZone.parkingZoneId, - parkingZone.link + "", + "" ).mkString(",") } .mkString(System.lineSeparator()) diff --git a/src/main/scala/beam/utils/MathUtils.scala b/src/main/scala/beam/utils/MathUtils.scala index 162365feb9f..17f5eb6a747 100755 --- a/src/main/scala/beam/utils/MathUtils.scala +++ b/src/main/scala/beam/utils/MathUtils.scala @@ -181,4 +181,6 @@ object MathUtils { }.toArray } } + + def selectRandomElement[T](xs: IndexedSeq[T], random: Random): T = xs(random.nextInt(xs.size)) } diff --git a/src/test/scala/beam/agentsim/infrastructure/ChargingNetworkManagerSpec.scala b/src/test/scala/beam/agentsim/infrastructure/ChargingNetworkManagerSpec.scala index 454f23cd44c..5bcaceb569f 100644 --- a/src/test/scala/beam/agentsim/infrastructure/ChargingNetworkManagerSpec.scala +++ b/src/test/scala/beam/agentsim/infrastructure/ChargingNetworkManagerSpec.scala @@ -125,8 +125,7 @@ class ChargingNetworkManagerSpec val personId: Id[Person] = Id.createPersonId("dummyPerson") - val parkingZoneId: Id[ParkingZoneId] = - ParkingZone.createId("cs_default(Any)_2_Public_ultrafast(250.0|DC)_FlatFee_0_1") + val parkingZoneId: Id[ParkingZoneId] = ParkingZone.createId("0") val parkingStall: ParkingStall = ParkingStall( diff --git a/src/test/scala/beam/agentsim/infrastructure/HierarchicalParkingManagerSpec.scala b/src/test/scala/beam/agentsim/infrastructure/HierarchicalParkingManagerSpec.scala index 6e9f42fb58c..ee1a055045c 100644 --- a/src/test/scala/beam/agentsim/infrastructure/HierarchicalParkingManagerSpec.scala +++ b/src/test/scala/beam/agentsim/infrastructure/HierarchicalParkingManagerSpec.scala @@ -191,7 +191,7 @@ class HierarchicalParkingManagerSpec ParkingStall( Id.create(1, classOf[TAZ]), Id.create(1, classOf[TAZ]), - ParkingZone.createId("cs_default(Any)_1_Workplace_NA_FlatFee_1234_1"), + ParkingZone.createId("0"), coordCenterOfUTM, 12.34, None, @@ -265,7 +265,7 @@ class HierarchicalParkingManagerSpec ParkingStall( expectedTAZId, expectedTAZId, - ParkingZone.createId("cs_default(Any)_1_Workplace_NA_FlatFee_1234_1"), + ParkingZone.createId("0"), coordCenterOfUTM, 12.34, None, diff --git a/src/test/scala/beam/agentsim/infrastructure/HierarchicalParkingManagerUtilSpec.scala b/src/test/scala/beam/agentsim/infrastructure/HierarchicalParkingManagerUtilSpec.scala index a7f00d5cba9..5209dd515ef 100644 --- a/src/test/scala/beam/agentsim/infrastructure/HierarchicalParkingManagerUtilSpec.scala +++ b/src/test/scala/beam/agentsim/infrastructure/HierarchicalParkingManagerUtilSpec.scala @@ -4,10 +4,11 @@ import beam.agentsim.infrastructure.charging.ChargingPointType.CustomChargingPoi import beam.agentsim.infrastructure.charging.ElectricCurrentType.DC import beam.agentsim.infrastructure.parking.ParkingType.Residential import beam.agentsim.infrastructure.parking.ParkingZoneFileUtilsSpec.PositiveTestData -import beam.agentsim.infrastructure.parking.{LinkLevelOperations, ParkingZone, ParkingZoneFileUtils} +import beam.agentsim.infrastructure.parking.{LinkLevelOperations, ParkingZone, ParkingZoneFileUtils, ParkingZoneId} import beam.agentsim.infrastructure.taz.{TAZ, TAZTreeMap} import org.matsim.api.core.v01.Id import org.matsim.api.core.v01.network.Link +import org.scalatest.LoneElement.convertToCollectionLoneElementWrapper import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec @@ -30,13 +31,15 @@ class HierarchicalParkingManagerUtilSpec extends AnyWordSpec with Matchers { Id.createLinkId(49577) -> Id.create(100026, classOf[TAZ]), Id.createLinkId(83658) -> Id.create(100026, classOf[TAZ]), Id.createLinkId(83661) -> Id.create(100026, classOf[TAZ]), - Id.createLinkId(83663) -> Id.create(100100, classOf[TAZ]) + Id.createLinkId(83663) -> Id.create(100100, classOf[TAZ]), + Id.createLinkId(83664) -> Id.create(100100, classOf[TAZ]) ) - private val (tazZones, _) = + private val (tazZones, linkZoneToTazZoneMap) = HierarchicalParkingManager.convertToTazParkingZones(linkZones.toMap, linkToTazMapping) println(tazZones.mkString("Array(", ", ", ")")) + println(linkZoneToTazZoneMap.mkString("Array(", ", ", ")")) tazZones.size should be(9) val joinZone: Option[ParkingZone[TAZ]] = tazZones.values.find { zone => zone.geoId.toString == "100026" && zone.parkingType == Residential && zone.chargingPointType.contains( @@ -47,6 +50,27 @@ class HierarchicalParkingManagerUtilSpec extends AnyWordSpec with Matchers { joinZone shouldBe defined joinZone.get.maxStalls should be(1100) tazZones.count(_._2.geoId.toString == "100100") should be(2) + + val zoneOfTaz100100 = tazZones.values + .filter(zone => + zone.geoId.toString == "100100" + && zone.chargingPointType.exists(_.toString.startsWith("ultrafast")) + ) + .loneElement + withClue("Two similar link zones should be collapsed to a single one") { + zoneOfTaz100100.maxStalls should be(20000) + zoneOfTaz100100.stallsAvailable should be(20000) + } + withClue("For each link zone should be created an entry in linkZoneToTazZoneMap") { + linkZoneToTazZoneMap should have size 11 + } + withClue("link zones 4, 7 and 10, 11 should be collapsed into single taz zones") { + val groupedByTazZone: IndexedSeq[Set[Id[ParkingZoneId]]] = + linkZoneToTazZoneMap.groupBy { case (_, tazZoneId) => tazZoneId }.values.map(_.keySet).toIndexedSeq + val (singles, collapsed) = groupedByTazZone.partition(_.size == 1) + singles should have size 7 + collapsed.map(_.map(_.toString)) should contain theSameElementsAs (Seq(Set("4", "7"), Set("10", "11"))) + } } } "creates taz link quad tree mapping" should { @@ -77,25 +101,6 @@ class HierarchicalParkingManagerUtilSpec extends AnyWordSpec with Matchers { "323" ) } - "collapsing parking zones " should { - "produce a simplified structure" in { - val (parkingZones, _) = - ParkingZoneFileUtils - .fromFile[Link]( - "test/test-resources/beam/agentsim/infrastructure/taz-parking-similar-zones.csv", - new Random(777934L), - None, - None - ) - parkingZones should have size 2990 - val zones205 = parkingZones.filter(_._2.geoId.toString == "205") - zones205 should have size 16 - val collapsed = HierarchicalParkingManager.collapse(parkingZones) - val collapsedZones205 = collapsed.filter(_._2.geoId.toString == "205") - collapsedZones205 should have size 11 - collapsed should have size 2236 - } - } } } } diff --git a/src/test/scala/beam/agentsim/infrastructure/ParallelParkingManagerSpec.scala b/src/test/scala/beam/agentsim/infrastructure/ParallelParkingManagerSpec.scala index 5853eefd418..8ffb341e0d4 100644 --- a/src/test/scala/beam/agentsim/infrastructure/ParallelParkingManagerSpec.scala +++ b/src/test/scala/beam/agentsim/infrastructure/ParallelParkingManagerSpec.scala @@ -8,7 +8,7 @@ import beam.agentsim.agents.BeamvilleFixtures import beam.agentsim.agents.vehicles.VehicleManager import beam.agentsim.agents.vehicles.VehicleManager.ReservedFor import beam.agentsim.events.SpaceTime -import beam.agentsim.infrastructure.parking.PricingModel.FlatFee +import beam.agentsim.infrastructure.parking.PricingModel.{Block, FlatFee} import beam.agentsim.infrastructure.parking._ import beam.agentsim.infrastructure.taz.{TAZ, TAZTreeMap} import beam.sim.common.GeoUtilsImpl @@ -150,8 +150,8 @@ class ParallelParkingManagerSpec 10000000 ) // one TAZ at agent coordinate oneParkingOption: Iterator[String] = - """taz,parkingType,pricingModel,chargingPointType,numStalls,feeInCents,reservedFor - |1,Workplace,FlatFee,None,1,1234, + """taz,parkingZoneId,parkingType,pricingModel,chargingPointType,numStalls,feeInCents,reservedFor + |1,a,Workplace,FlatFee,None,1,1234, | """.stripMargin.split("\n").toIterator random = new Random(randomSeed) @@ -173,7 +173,7 @@ class ParallelParkingManagerSpec ParkingStall( Id.create(1, classOf[TAZ]), Id.create(1, classOf[TAZ]), - ParkingZone.createId("cs_default(Any)_1_Workplace_NA_FlatFee_1234_1"), + ParkingZone.createId("a"), coordCenterOfUTM, 12.34, None, @@ -214,8 +214,8 @@ class ParallelParkingManagerSpec 10000000 ) // one TAZ at agent coordinate oneParkingOption: Iterator[String] = - """taz,parkingType,pricingModel,chargingPointType,numStalls,feeInCents,reservedFor - |1,Workplace,FlatFee,None,1,1234, + """taz,parkingZoneId,parkingType,pricingModel,chargingPointType,numStalls,feeInCents,reservedFor + |1,a,Workplace,FlatFee,None,1,1234, | """.stripMargin.split("\n").toIterator random = new Random(randomSeed) @@ -239,7 +239,7 @@ class ParallelParkingManagerSpec ParkingStall( expectedTAZId, expectedTAZId, - ParkingZone.createId("cs_default(Any)_1_Workplace_NA_FlatFee_1234_1"), + ParkingZone.createId("a"), coordCenterOfUTM, 12.34, None, @@ -362,7 +362,7 @@ class ParallelParkingManagerSpec zpm, new Coord(170308.0, 2964.0), "4", - ParkingZone.createId("cs_default(Any)_4_Residential_NA_FlatFee_0_2147483647"), + ParkingZone.createId("73"), FlatFee(0.0), ParkingType.Residential, VehicleManager.AnyManager @@ -372,7 +372,7 @@ class ParallelParkingManagerSpec zpm, new Coord(166321.0, 1568.0), "1", - ParkingZone.createId("cs_default(Any)_1_Residential_NA_FlatFee_0_2147483647"), + ParkingZone.createId("22"), FlatFee(0.0), ParkingType.Residential, VehicleManager.AnyManager @@ -382,8 +382,8 @@ class ParallelParkingManagerSpec zpm, new Coord(167141.3, 3326.017), "2", - ParkingZone.createId("cs_default(Any)_2_Residential_NA_FlatFee_0_2147483647"), - FlatFee(0.0), + ParkingZone.createId("15"), + Block(0.0, 3600), ParkingType.Residential, VehicleManager.AnyManager ) diff --git a/src/test/scala/beam/agentsim/infrastructure/ZonalParkingManagerSpec.scala b/src/test/scala/beam/agentsim/infrastructure/ZonalParkingManagerSpec.scala index ba0a59e18cd..6fd345bb429 100644 --- a/src/test/scala/beam/agentsim/infrastructure/ZonalParkingManagerSpec.scala +++ b/src/test/scala/beam/agentsim/infrastructure/ZonalParkingManagerSpec.scala @@ -9,7 +9,7 @@ import beam.agentsim.agents.vehicles.EnergyEconomyAttributes.Powertrain import beam.agentsim.agents.vehicles.VehicleManager.ReservedFor import beam.agentsim.agents.vehicles.{BeamVehicle, BeamVehicleType, VehicleManager} import beam.agentsim.events.SpaceTime -import beam.agentsim.infrastructure.parking.PricingModel.FlatFee +import beam.agentsim.infrastructure.parking.PricingModel.{Block, FlatFee} import beam.agentsim.infrastructure.parking._ import beam.agentsim.infrastructure.taz.{TAZ, TAZTreeMap} import beam.sim.common.{GeoUtils, GeoUtilsImpl} @@ -336,7 +336,7 @@ class ZonalParkingManagerSpec zpm, SpaceTime(new Coord(170308.0, 2964.0), 0), "4", - ParkingZone.createId("cs_default(Any)_4_Residential_NA_FlatFee_0_2147483647"), + ParkingZone.createId("73"), FlatFee(0.0), ParkingType.Residential, "beamVilleCar" @@ -346,7 +346,7 @@ class ZonalParkingManagerSpec zpm, SpaceTime(new Coord(166321.0, 1568.0), 0), "1", - ParkingZone.createId("cs_default(Any)_1_Residential_NA_FlatFee_0_2147483647"), + ParkingZone.createId("22"), FlatFee(0.0), ParkingType.Residential, "beamVilleCar" @@ -356,8 +356,8 @@ class ZonalParkingManagerSpec zpm, SpaceTime(new Coord(167141.3, 3326.017), 0), "2", - ParkingZone.createId("cs_default(Any)_2_Residential_NA_FlatFee_0_2147483647"), - FlatFee(0.0), + ParkingZone.createId("15"), + Block(0.0, 3600), ParkingType.Residential, "beamVilleCar" ) @@ -370,8 +370,8 @@ class ZonalParkingManagerSpec it("should return a stall from the single available zone (index=2)") { val parkingDescription: Iterator[String] = """taz,parkingType,pricingModel,chargingPointType,numStalls,feeInCents,timeRestrictions,reservedFor,parkingZoneId - |4,Public,FlatFee,NoCharger,10,0,Car|0-17:30;LightDutyTruck|17:31-23:59,, - |4,Public,Block,NoCharger,20,0,LightDutyTruck|0-17:30;Car|17:31-23:59,,""".stripMargin + |4,Public,FlatFee,NoCharger,10,0,Car|0-17:30;LightDutyTruck|17:31-23:59,,a + |4,Public,Block,NoCharger,20,0,LightDutyTruck|0-17:30;Car|17:31-23:59,,b""".stripMargin .split("\n") .toIterator val tazMap = taz.TAZTreeMap.fromCsv("test/input/beamville/taz-centers.csv") @@ -396,7 +396,7 @@ class ZonalParkingManagerSpec zpm, SpaceTime(new Coord(169369.8, 3326.017), 8 * 3600), "4", - ParkingZone.createId("cs_default(Any)_4_Public_NA_Block_0_20"), + ParkingZone.createId("b"), PricingModel("block", "0").get, ParkingType.Public, "FREIGHT-1" @@ -448,7 +448,7 @@ class ZonalParkingManagerSpec zonesMap, SpaceTime(new Coord(170308.0, 2964.0), 0), "4", - ParkingZone.createId("cs_default(Any)_4_Residential_NA_FlatFee_199_1144"), + ParkingZone.createId("73"), FlatFee(1.99), ParkingType.Residential, "beamVilleCar" diff --git a/src/test/scala/beam/agentsim/infrastructure/parking/ParkingZoneFileUtilsSpec.scala b/src/test/scala/beam/agentsim/infrastructure/parking/ParkingZoneFileUtilsSpec.scala index 9cb19a21067..59588d55827 100644 --- a/src/test/scala/beam/agentsim/infrastructure/parking/ParkingZoneFileUtilsSpec.scala +++ b/src/test/scala/beam/agentsim/infrastructure/parking/ParkingZoneFileUtilsSpec.scala @@ -186,15 +186,12 @@ class ParkingZoneFileUtilsSpec extends AnyWordSpec with Matchers { None, None ) - parkingZones should have size 2990 - val collapsed = HierarchicalParkingManager.collapse(parkingZones) - val collapsedZones205 = collapsed.filter(_._2.geoId.toString == "205") - collapsedZones205 should have size 11 - val zoneSearchTree = ParkingZoneFileUtils.createZoneSearchTree(collapsed.values.toSeq) + parkingZones should have size 3648 + val zoneSearchTree = ParkingZoneFileUtils.createZoneSearchTree(parkingZones.values.toSeq) val subTree = zoneSearchTree(Id.create("205", classOf[Link])) - subTree.values.map(_.length).sum should be(11) - subTree(Public) should have length 4 - subTree(Workplace) should have length 3 + subTree.values.map(_.length).sum should be(20) + subTree(Public) should have length 12 + subTree(Workplace) should have length 4 subTree(Residential) should have length 4 } } @@ -233,17 +230,18 @@ object ParkingZoneFileUtilsSpec { """.stripMargin.split("\n").toIterator val linkLevelData: Iterator[String] = - """taz,parkingType,pricingModel,chargingPointType,numStalls,feeInCents,reservedFor - |49577,Residential,FlatFee,level1(2.3|AC),10,0.0, - |49577,Public,Block,level2(7.2|AC),10,0.0, - |49577,Workplace,FlatFee,dcfast(50.0|DC),10,0.0, - |83658,Residential,Block,dcfast(50.0|DC),100,0.0, - |83658,Residential,FlatFee,NoCharger,100,0.0, - |83658,Workplace,FlatFee,ultrafast(250.0|DC),100,0.0, - |83661,Residential,Block,dcfast(50.0|DC),1000,0.0, - |83661,Public,FlatFee,level2(7.2|AC),1000,0.0, - |83663,Workplace,FlatFee,level2(7.2|AC),10000,0.0, - |83663,Workplace,FlatFee,ultrafast(250.0|DC),10000,0.0, + """taz,parkingZoneId,parkingType,pricingModel,chargingPointType,numStalls,feeInCents,reservedFor + |49577,1,Residential,FlatFee,level1(2.3|AC),10,0.0, + |49577,2,Public,Block,level2(7.2|AC),10,0.0, + |49577,3,Workplace,FlatFee,dcfast(50.0|DC),10,0.0, + |83658,4,Residential,Block,dcfast(50.0|DC),100,0.0, + |83658,5,Residential,FlatFee,NoCharger,100,0.0, + |83658,6,Workplace,FlatFee,ultrafast(250.0|DC),100,0.0, + |83661,7,Residential,Block,dcfast(50.0|DC),1000,0.0, + |83661,8,Public,FlatFee,level2(7.2|AC),1000,0.0, + |83663,9,Workplace,FlatFee,level2(7.2|AC),10000,0.0, + |83663,10,Workplace,FlatFee,ultrafast(250.0|DC),10000,0.0, + |83664,11,Workplace,FlatFee,ultrafast(250.0|DC),10000,0.0, | """.stripMargin.split("\n").toIterator diff --git a/test/input/sf-light/link-parking.csv b/test/input/sf-light/link-parking.csv deleted file mode 100644 index 1c411d89567..00000000000 --- a/test/input/sf-light/link-parking.csv +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3d4326eb5e3e4a19b0a2f42dcb13ed6d6426059843c87d77a0a03ca5b9f506c8 -size 159685528 diff --git a/test/input/sf-light/link-parking.csv.gz b/test/input/sf-light/link-parking.csv.gz index 7f01d991d2a..90baf167b1b 100644 --- a/test/input/sf-light/link-parking.csv.gz +++ b/test/input/sf-light/link-parking.csv.gz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:549d0061865bec1e80b560fa96f8e57e34ef5071b8fa5d9b7684b09132ef2e59 -size 10005189 +oid sha256:fc72ca12488c6d54abf07ac5134c56a9d0022456e7799b69cc96c4b84ffd78ec +size 10005205 diff --git a/test/input/sf-light/sf-light-1k-csv-linkparking-pickups-dropoffs.conf b/test/input/sf-light/sf-light-1k-csv-linkparking-pickups-dropoffs.conf index 3125176a563..90998e0d9eb 100755 --- a/test/input/sf-light/sf-light-1k-csv-linkparking-pickups-dropoffs.conf +++ b/test/input/sf-light/sf-light-1k-csv-linkparking-pickups-dropoffs.conf @@ -3,9 +3,9 @@ include "sf-light-1k-csv.conf" beam.agentsim.simulationName = "sf-light-1k-csv-with-link-parking" beam.agentsim.firstIteration = 0 -beam.agentsim.lastIteration = 2 +beam.agentsim.lastIteration = 0 -beam.agentsim.taz.parkingFilePath = "test/input/sf-light/link-parking.csv" +beam.agentsim.taz.parkingFilePath = "test/input/sf-light/link-parking.csv.gz" beam.agentsim.taz.parkingManager.name = "HIERARCHICAL" beam.physsim.jdeqsim.cacc.enabled = false diff --git a/test/input/sf-light/sf-light-25k-experiment-2.conf b/test/input/sf-light/sf-light-25k-experiment-2.conf index f27d1068334..cac735ef57c 100755 --- a/test/input/sf-light/sf-light-25k-experiment-2.conf +++ b/test/input/sf-light/sf-light-25k-experiment-2.conf @@ -2,7 +2,7 @@ include "sf-light-25k-experiment-1.conf" beam.agentsim.simulationName = "sf-light-25k-linkparking" -beam.agentsim.taz.parkingFilePath = "test/input/sf-light/link-parking.csv" +beam.agentsim.taz.parkingFilePath = "test/input/sf-light/link-parking.csv.gz" beam.agentsim.taz.parkingManager.name = "HIERARCHICAL" diff --git a/test/input/sf-light/sf-light-25k-experiment-3.conf b/test/input/sf-light/sf-light-25k-experiment-3.conf index 3a589d416a5..90137253793 100755 --- a/test/input/sf-light/sf-light-25k-experiment-3.conf +++ b/test/input/sf-light/sf-light-25k-experiment-3.conf @@ -2,7 +2,7 @@ include "sf-light-25k-experiment-1.conf" beam.agentsim.simulationName = "sf-light-25k-linkparking-light-pd" -beam.agentsim.taz.parkingFilePath = "test/input/sf-light/link-parking.csv" +beam.agentsim.taz.parkingFilePath = "test/input/sf-light/link-parking.csv.gz" beam.agentsim.taz.parkingManager.name = "HIERARCHICAL" beam.physsim.pickUpDropOffAnalysis.enabled = true diff --git a/test/input/sf-light/sf-light-25k-experiment-4.conf b/test/input/sf-light/sf-light-25k-experiment-4.conf index c987c1d06f8..f9c84ebe48a 100755 --- a/test/input/sf-light/sf-light-25k-experiment-4.conf +++ b/test/input/sf-light/sf-light-25k-experiment-4.conf @@ -2,7 +2,7 @@ include "sf-light-25k-experiment-1.conf" beam.agentsim.simulationName = "sf-light-25k-linkparking-medium-pd" -beam.agentsim.taz.parkingFilePath = "test/input/sf-light/link-parking.csv" +beam.agentsim.taz.parkingFilePath = "test/input/sf-light/link-parking.csv.gz" beam.agentsim.taz.parkingManager.name = "HIERARCHICAL" beam.physsim.pickUpDropOffAnalysis.enabled = true diff --git a/test/input/sf-light/sf-light-25k-experiment-5.conf b/test/input/sf-light/sf-light-25k-experiment-5.conf index ef25b204768..dcfe7ac4f1e 100755 --- a/test/input/sf-light/sf-light-25k-experiment-5.conf +++ b/test/input/sf-light/sf-light-25k-experiment-5.conf @@ -2,7 +2,7 @@ include "sf-light-25k-experiment-1.conf" beam.agentsim.simulationName = "sf-light-25k-linkparking-heavy-pd" -beam.agentsim.taz.parkingFilePath = "test/input/sf-light/link-parking.csv" +beam.agentsim.taz.parkingFilePath = "test/input/sf-light/link-parking.csv.gz" beam.agentsim.taz.parkingManager.name = "HIERARCHICAL" beam.physsim.pickUpDropOffAnalysis.enabled = true From 977f902c17847c849ed46300c3acd89a45378467 Mon Sep 17 00:00:00 2001 From: Dmitry Openkov Date: Tue, 22 Mar 2022 10:51:44 +0300 Subject: [PATCH 02/25] Referring to an existing link parking file in production/sfbay --- .../agentsim/infrastructure/ParkingManagerBenchmark.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/beam/agentsim/infrastructure/ParkingManagerBenchmark.scala b/src/main/scala/beam/agentsim/infrastructure/ParkingManagerBenchmark.scala index eb20f701ff3..37f9bf2f741 100644 --- a/src/main/scala/beam/agentsim/infrastructure/ParkingManagerBenchmark.scala +++ b/src/main/scala/beam/agentsim/infrastructure/ParkingManagerBenchmark.scala @@ -66,7 +66,7 @@ object ParkingManagerBenchmark extends StrictLogging { // val pathToTazParking: String = // "https://beam-outputs.s3.us-east-2.amazonaws.com/parallel_parking_manager/taz-parking-unlimited-fast-limited-l2-150-baseline.csv.gz" - val pathToLinkParking: String = "data_files/sfbay-smartbaseline/link-parking.csv" + val pathToLinkParking: String = "production/sfbay/parking/init1-7_2022_Feb_03_wgs84_withFees_link.csv" // val pathToLinkParking: String = // "https://beam-outputs.s3.us-east-2.amazonaws.com/parallel_parking_manager/link-parking-unlimited-fast-limited-l2-150-baseline.csv.gz" @@ -109,7 +109,7 @@ object ParkingManagerBenchmark extends StrictLogging { val seed: Int = 42 val nTimes: Int = 1 - val fractionToBench: Double = 0.5 + val fractionToBench: Double = 0.05 def main(args: Array[String]): Unit = { implicit val ec: ExecutionContext = scala.concurrent.ExecutionContext.Implicits.global @@ -289,7 +289,7 @@ object ParkingManagerBenchmark extends StrictLogging { }) logger.info("activities written") - val (result, responses) = benchmark("hierarchical-taz", nTimes, parkingLocations) + val (result, responses) = benchmark("hierarchical", nTimes, parkingLocations) val (zonalResult, zonalResponses) = benchmark("zonal", nTimes, parkingLocations) logger.info("#####################################################################") From a42f2baea4d07ea73cc53c5f7fa136a01fd98fa4 Mon Sep 17 00:00:00 2001 From: Dmitry Openkov Date: Fri, 15 Apr 2022 16:04:10 +0300 Subject: [PATCH 03/25] TazToLinkLevelParkingApp uses generateLinkParkingOutOfTazParking method --- .../parking/ParkingZoneFileUtils.scala | 2 +- .../parking/TazToLinkLevelParkingApp.scala | 81 +++---------------- test/input/sf-light/taz-parking.csv | 4 +- 3 files changed, 15 insertions(+), 72 deletions(-) diff --git a/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZoneFileUtils.scala b/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZoneFileUtils.scala index 836e2d04381..30c820cc30e 100644 --- a/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZoneFileUtils.scala +++ b/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZoneFileUtils.scala @@ -149,7 +149,7 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { case None => "NoCharger" case Some(cp) => s"$cp" } - val reservedFor = parkingZone.reservedFor.toString.mkString("|") + val reservedFor = parkingZone.reservedFor.toString val timeRestrictions = parkingZone.timeRestrictions.map(toString).mkString("|") val parkingZoneIdStr = parkingZone.parkingZoneId.toString val (locationXStr, locationYStr) = diff --git a/src/main/scala/beam/agentsim/infrastructure/parking/TazToLinkLevelParkingApp.scala b/src/main/scala/beam/agentsim/infrastructure/parking/TazToLinkLevelParkingApp.scala index e6038429ada..8d4055e4c55 100644 --- a/src/main/scala/beam/agentsim/infrastructure/parking/TazToLinkLevelParkingApp.scala +++ b/src/main/scala/beam/agentsim/infrastructure/parking/TazToLinkLevelParkingApp.scala @@ -7,7 +7,9 @@ import org.matsim.api.core.v01.Id import org.matsim.api.core.v01.network.Link import org.matsim.core.network.NetworkUtils import org.matsim.core.network.io.MatsimNetworkReader +import org.matsim.core.utils.collections.QuadTree +import scala.collection.JavaConverters._ import scala.util.Random /** @@ -30,7 +32,7 @@ object TazToLinkLevelParkingApp extends App with StrictLogging { .toMap } - val argsMap = parseArgs(args) + private val argsMap = parseArgs(args) if (argsMap.size != 4) { println( @@ -42,46 +44,28 @@ object TazToLinkLevelParkingApp extends App with StrictLogging { } logger.info("args = {}", argsMap) - val tazMap = TAZTreeMap.getTazTreeMap(argsMap("taz-centers")) + private val tazMap = TAZTreeMap.getTazTreeMap(argsMap("taz-centers")) - val network = { + private val network = { val network = NetworkUtils.createNetwork() new MatsimNetworkReader(network).readFile(argsMap("network")) network } - val (parkingZones: Map[Id[ParkingZoneId], ParkingZone[TAZ]], zoneSearchTree: ZoneSearchTree[TAZ]) = + private val (parkingZones: Map[Id[ParkingZoneId], ParkingZone[TAZ]], _: ZoneSearchTree[TAZ]) = ParkingZoneFileUtils.fromFile[TAZ](argsMap("taz-parking"), new Random(), None, None) - val linkToTaz = LinkLevelOperations.getLinkToTazMapping(network, tazMap) + private val linkToTaz = LinkLevelOperations.getLinkToTazMapping(network, tazMap) logger.info(s"Number of links in the network: ${linkToTaz.size}") - val tazToLinks: Map[TAZ, List[Link]] = linkToTaz.groupBy(_._2).mapValues(_.keys.toList) + private val linkQuadTree: QuadTree[Link] = + LinkLevelOperations.getLinkTreeMap(network.getLinks.values().asScala.toSeq) - val zonesLink: Iterable[ParkingZone[Link]] = tazToLinks.flatMap { case (taz, links) => - distributeParking(taz, links, parkingZones, zoneSearchTree) - } - - val zoneArrayLink: Map[Id[ParkingZoneId], ParkingZone[Link]] = zonesLink - .filter(_.maxStalls > 0) - .zipWithIndex - .map { case (zone, _) => - val zoneId = ParkingZone.init[Link]( - None, - geoId = zone.geoId, - parkingType = zone.parkingType, - maxStalls = zone.maxStalls, - reservedFor = zone.reservedFor, - chargingPointType = zone.chargingPointType, - pricingModel = zone.pricingModel, - timeRestrictions = zone.timeRestrictions - ) - zoneId.parkingZoneId -> zoneId - } - .toMap + private val zoneArrayLink: Map[Id[ParkingZoneId], ParkingZone[Link]] = + ParkingZoneFileUtils.generateLinkParkingOutOfTazParking(parkingZones, linkQuadTree, linkToTaz, tazMap) - val zoneSearchTreeLink = zoneArrayLink.values + private val zoneSearchTreeLink = zoneArrayLink.values .groupBy(_.geoId) .mapValues { zones => zones @@ -93,45 +77,4 @@ object TazToLinkLevelParkingApp extends App with StrictLogging { logger.info("with {} parking stalls", zoneArrayLink.map(_._2.stallsAvailable.toLong).sum) ParkingZoneFileUtils.writeParkingZoneFile(zoneSearchTreeLink, zoneArrayLink, argsMap("out")) - private def distributeParking( - taz: TAZ, - links: List[Link], - parkingZones: Map[Id[ParkingZoneId], ParkingZone[TAZ]], - zoneSearchTree: ZoneSearchTree[TAZ] - ) = { - val totalLength = links.map(_.getLength).sum - val tazParkingZones = for { - parkingTypesSubtree <- zoneSearchTree.get(taz.tazId).toList - parkingType <- ParkingType.AllTypes - parkingZoneIds <- parkingTypesSubtree.get(parkingType).toList - parkingZoneId <- parkingZoneIds - parkingZone <- ParkingZone.getParkingZone(parkingZones, parkingZoneId) - } yield { - parkingZone - } - - links.flatMap { link => -// take random n zones for each link and scale their parking slot number -// val n = 3 -// val randomZones = Random.shuffle(tazParkingZones).take(n) - val randomZones = tazParkingZones - val multiplier = randomZones.size.toDouble / tazParkingZones.size - randomZones.map { zone => - val zonesPerMeter = zone.maxStalls * multiplier / totalLength - val numZones = Math.round(zonesPerMeter * link.getLength).toInt - ParkingZone.init[Link]( - None, - geoId = link.getId, - parkingType = zone.parkingType, - maxStalls = numZones, - reservedFor = zone.reservedFor, - chargingPointType = zone.chargingPointType, - pricingModel = zone.pricingModel, - timeRestrictions = zone.timeRestrictions - ) - } - } - - } - } diff --git a/test/input/sf-light/taz-parking.csv b/test/input/sf-light/taz-parking.csv index a5dfbaa4832..e8e022501d9 100644 --- a/test/input/sf-light/taz-parking.csv +++ b/test/input/sf-light/taz-parking.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ec529a2d978a87a4117a19b4f8cada0f9c521faa21c3578a17d91aa4298a1b28 -size 1636492 +oid sha256:093a26c285c5bd9ca090c185697778e3f4ac663eae6ca33e5188f21157372e24 +size 1636497 From 5e3e9f4cd4d949f0839819ca34ac1d2c8971673d Mon Sep 17 00:00:00 2001 From: Nikolay Ilyin Date: Tue, 19 Apr 2022 21:56:45 +0300 Subject: [PATCH 04/25] multithreading sorting of events --- .../beam_to_matsim/EventsByVehicleMode.scala | 2 +- .../beam/utils/beam_to_matsim/io/Reader.scala | 24 +++---- .../beam/utils/beam_to_matsim/io/Writer.scala | 30 ++++++++- .../via_event/ViaEventsCollection.scala | 21 +++++++ .../visualization/via/visualization_11.scala | 2 +- .../via/visualization_20_24.scala | 6 +- .../via/visualization_33_34.scala | 2 +- .../visualization/via/visualization_35.scala | 2 +- .../via/visualization_3_4_5.scala | 2 +- .../visualization/via/visualization_6.scala | 2 +- .../utils/beam_to_matsim/io/WriterTest.scala | 63 +++++++++++++++++++ 11 files changed, 132 insertions(+), 24 deletions(-) create mode 100644 src/main/scala/beam/utils/beam_to_matsim/via_event/ViaEventsCollection.scala create mode 100644 src/test/scala/beam/utils/beam_to_matsim/io/WriterTest.scala diff --git a/src/main/scala/beam/utils/beam_to_matsim/EventsByVehicleMode.scala b/src/main/scala/beam/utils/beam_to_matsim/EventsByVehicleMode.scala index f3cd4a831fd..e51a174ba18 100644 --- a/src/main/scala/beam/utils/beam_to_matsim/EventsByVehicleMode.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/EventsByVehicleMode.scala @@ -98,7 +98,7 @@ object EventsByVehicleMode extends App { val (vehiclesEvents, _) = Reader.readWithFilter(eventsFile, filter) val (events, typeToId) = Reader.transformPathTraversals(vehiclesEvents, vehicleId, vehicleType) - Writer.writeViaEventsQueue[ViaEvent](events, _.toXmlString, outputFile) + Writer.writeViaEventsQueue(events, _.toXmlString, outputFile) Writer.writeViaIdFile(typeToId, outputFile + ".ids.txt") } diff --git a/src/main/scala/beam/utils/beam_to_matsim/io/Reader.scala b/src/main/scala/beam/utils/beam_to_matsim/io/Reader.scala index 7e63351888c..9500d6a394b 100644 --- a/src/main/scala/beam/utils/beam_to_matsim/io/Reader.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/io/Reader.scala @@ -2,7 +2,7 @@ package beam.utils.beam_to_matsim.io import beam.utils.beam_to_matsim.events.{BeamActivityEnd, BeamActivityStart, BeamModeChoice, BeamPathTraversal} import beam.utils.beam_to_matsim.events_filter.{MutableSamplingFilter, PersonEvents, VehicleTrip} -import beam.utils.beam_to_matsim.via_event._ +import beam.utils.beam_to_matsim.via_event.{ViaEventsCollection, _} import scala.collection.mutable @@ -25,7 +25,8 @@ object Reader { .getOrElse(filter) // fix overlapping of path traversal events for vehicle - def pteOverlappingFix(pteSeq: Seq[BeamPathTraversal]): Unit = { + def pteOverlappingFix(pteSeqRaw: Seq[BeamPathTraversal]): Unit = { + val pteSeq = pteSeqRaw.filter(pte => pte.linkTravelTime.isEmpty) @SuppressWarnings(Array("UnsafeTraversableMethods")) val pteSeqHead = pteSeq.head pteSeq.drop(1).foldLeft(pteSeqHead) { @@ -152,13 +153,12 @@ object Reader { vehiclesTrips: Traversable[VehicleTrip], vehicleId: BeamPathTraversal => String, vehicleType: BeamPathTraversal => String - ): (mutable.PriorityQueue[ViaEvent], mutable.Map[String, mutable.HashSet[String]]) = { + ): (ViaEventsCollection, mutable.Map[String, mutable.HashSet[String]]) = { case class ViaEventsCollector( vehicleId: BeamPathTraversal => String, vehicleType: BeamPathTraversal => String, - events: mutable.PriorityQueue[ViaEvent] = - mutable.PriorityQueue.empty[ViaEvent]((e1, e2) => e2.time.compare(e1.time)), + eventsCollection: ViaEventsCollection = new ViaEventsCollection(), vehicleTypeToId: mutable.Map[String, mutable.HashSet[String]] = mutable.Map.empty[String, mutable.HashSet[String]] ) { def collectVehicleTrip(ptEvents: Seq[BeamPathTraversal]): Unit = { @@ -166,7 +166,7 @@ object Reader { val minTimeIntervalForContinuousMovement = 40.0 case class EventsTransformer( - events: mutable.PriorityQueue[ViaEvent], + eventsCollection: ViaEventsCollection, var prevEvent: Option[ViaTraverseLinkEvent] = None ) { def addPTEEvent(curr: ViaTraverseLinkEvent): Unit = { @@ -197,17 +197,17 @@ object Reader { } prevEvent = Some(curr) - events.enqueue(curr) + eventsCollection.put(curr) } def addPersonArrival(time: Double, viaEvent: ViaTraverseLinkEvent): Unit = - events.enqueue(ViaPersonArrivalEvent(time + minTimeStep, viaEvent.vehicle, viaEvent.link)) + eventsCollection.put(ViaPersonArrivalEvent(time + minTimeStep, viaEvent.vehicle, viaEvent.link)) def addPersonDeparture(viaEvent: ViaTraverseLinkEvent): Unit = - events.enqueue(ViaPersonDepartureEvent(viaEvent.time + minTimeStep, viaEvent.vehicle, viaEvent.link)) + eventsCollection.put(ViaPersonDepartureEvent(viaEvent.time + minTimeStep, viaEvent.vehicle, viaEvent.link)) } - val transformer = ptEvents.foldLeft(EventsTransformer(events))((acc, pte) => { + val transformer = ptEvents.foldLeft(EventsTransformer(eventsCollection))((acc, pte) => { val vId = vehicleId(pte) pte.toViaEvents(vId, None).foreach(acc.addPTEEvent) @@ -239,9 +239,9 @@ object Reader { progress.finish() - Console.println(viaEventsCollector.events.size + " via events with vehicles trips") + Console.println(viaEventsCollector.eventsCollection.size + " via events with vehicles trips") Console.println(viaEventsCollector.vehicleTypeToId.size + " vehicle types") - (viaEventsCollector.events, viaEventsCollector.vehicleTypeToId) + (viaEventsCollector.eventsCollection, viaEventsCollector.vehicleTypeToId) } } diff --git a/src/main/scala/beam/utils/beam_to_matsim/io/Writer.scala b/src/main/scala/beam/utils/beam_to_matsim/io/Writer.scala index da8b3e289c3..e0750717da6 100644 --- a/src/main/scala/beam/utils/beam_to_matsim/io/Writer.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/io/Writer.scala @@ -1,9 +1,8 @@ package beam.utils.beam_to_matsim.io import java.io.{File, PrintWriter} - import beam.utils.FileUtils -import beam.utils.beam_to_matsim.via_event.ViaEvent +import beam.utils.beam_to_matsim.via_event.{ViaEvent, ViaEventsCollection} import scala.collection.mutable @@ -19,7 +18,6 @@ object Writer { val eventsCount = queue.size Console.println(s"started writing $eventsCount events ...") val progress = new ConsoleProgress("evenst written", eventsCount, 5) - FileUtils.using(new PrintWriter(new File(outputPath))) { pw => pw.println("\n") while (queue.nonEmpty) { @@ -35,6 +33,32 @@ object Writer { Console.println("via events written into " + outputPath) } + def writeViaEventsQueue( + eventsCollection: ViaEventsCollection, + transform: ViaEvent => String, + outputPath: String + ): Unit = { + val eventsCount = eventsCollection.size + Console.println(s"started writing $eventsCount events ...") + val progress = new ConsoleProgress("evenst written", eventsCount, 5) + + FileUtils.using(new PrintWriter(new File(outputPath))) { pw => + pw.println("\n") + + val sortedEvents = eventsCollection.getSortedEvents() + + sortedEvents.foreach { entry => + progress.step() + pw.println(transform(entry)) + } + pw.println("") + } + + progress.finish() + + Console.println("via events written into " + outputPath) + } + def writeSeqOfString(script: Traversable[String], outputPath: String): Unit = { FileUtils.using(new PrintWriter(new File(outputPath))) { pw => script.foreach(pw.println) diff --git a/src/main/scala/beam/utils/beam_to_matsim/via_event/ViaEventsCollection.scala b/src/main/scala/beam/utils/beam_to_matsim/via_event/ViaEventsCollection.scala new file mode 100644 index 00000000000..1b2ca4526a9 --- /dev/null +++ b/src/main/scala/beam/utils/beam_to_matsim/via_event/ViaEventsCollection.scala @@ -0,0 +1,21 @@ +package beam.utils.beam_to_matsim.via_event + +import scala.collection.mutable.ArrayBuffer + +class ViaEventsCollection { + + val unsortedEvents: ArrayBuffer[ViaEvent] = ArrayBuffer.empty[ViaEvent] + + def getSortedEvents: Seq[ViaEvent] = { + val arrayToSort = unsortedEvents.toArray + val comparator = new java.util.Comparator[ViaEvent] { + override def compare(ev1: ViaEvent, ev2: ViaEvent): Int = { + ev1.time.compare(ev2.time) + } + } + java.util.Arrays.parallelSort(arrayToSort, comparator) + arrayToSort + } + def put(event: ViaEvent): Unit = unsortedEvents.append(event) + def size: Int = unsortedEvents.length +} diff --git a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_11.scala b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_11.scala index 9ec30dad7b1..9ef03f87d7a 100755 --- a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_11.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_11.scala @@ -66,6 +66,6 @@ object visualization_11 extends App { val (vehiclesEvents, _) = Reader.readWithFilter(beamEventsFilePath, filter) val (events, typeToId) = Reader.transformPathTraversals(vehiclesEvents, vehicleId, vehicleType) - Writer.writeViaEventsQueue[ViaEvent](events, _.toXml.toString, viaEventsFile) + Writer.writeViaEventsQueue(events, _.toXml.toString, viaEventsFile) Writer.writeViaIdFile(typeToId, viaIdsFile) } diff --git a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_20_24.scala b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_20_24.scala index e70f39d0cd0..089227566df 100755 --- a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_20_24.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_20_24.scala @@ -25,12 +25,12 @@ object visualization_20_24 extends App { val (events, typeToId) = Reader.transformPathTraversals(vehiclesEvents, vehicleId, vehicleType) val (modeChoiceEvents, modeToCnt) = Reader.transformModeChoices(personsEvents, 20) - modeChoiceEvents.foreach(events.enqueue(_)) + modeChoiceEvents.foreach(events.put) val (activities, activityToCnt) = Reader.transformActivities(personsEvents) - activities.foreach(events.enqueue(_)) + activities.foreach(events.put) - Writer.writeViaEventsQueue[ViaEvent](events, _.toXml.toString, viaEventsFile) + Writer.writeViaEventsQueue(events, _.toXml.toString, viaEventsFile) Writer.writeViaActivities(activityToCnt, viaActivitiesFile) Writer.writeViaModes(modeToCnt, viaModesFile) diff --git a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_33_34.scala b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_33_34.scala index b2f9525b1ac..d9b15c8285c 100755 --- a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_33_34.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_33_34.scala @@ -46,6 +46,6 @@ object visualization_33_34 extends App { val (vehiclesEvents, _) = Reader.readWithFilter(beamEventsFilePath, MutableVehiclesFilter(Selector)) val (events, typeToId) = Reader.transformPathTraversals(vehiclesEvents, vehicleId, vehicleType) - Writer.writeViaEventsQueue[ViaEvent](events, _.toXml.toString, viaEventsFile) + Writer.writeViaEventsQueue(events, _.toXml.toString, viaEventsFile) Writer.writeViaIdFile(typeToId, viaIdsFile) } diff --git a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_35.scala b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_35.scala index 4d2469cc714..e165cae07f5 100755 --- a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_35.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_35.scala @@ -71,7 +71,7 @@ object visualization_35 extends App { val (events, typeToId) = Reader.transformPathTraversals(eventsWithAlternatives, vehicleId, vehicleType) - Writer.writeViaEventsQueue[ViaEvent](events, _.toXml.toString, viaEventsFile) + Writer.writeViaEventsQueue(events, _.toXml.toString, viaEventsFile) Writer.writeViaIdFile(typeToId, viaIdFile) } diff --git a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_3_4_5.scala b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_3_4_5.scala index adab5360a20..a85eda221de 100755 --- a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_3_4_5.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_3_4_5.scala @@ -61,6 +61,6 @@ object visualization_3_4_5 extends App { val (vehiclesEvents, _) = Reader.readWithFilter(beamEventsFilePath, filter) val (events, typeToId) = Reader.transformPathTraversals(vehiclesEvents, vehicleId, vehicleType) - Writer.writeViaEventsQueue[ViaEvent](events, _.toXml.toString, viaEventsFile) + Writer.writeViaEventsQueue(events, _.toXml.toString, viaEventsFile) Writer.writeViaIdFile(typeToId, viaIdsFile) } diff --git a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_6.scala b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_6.scala index 3a8a05bae1d..0ff74b88aeb 100755 --- a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_6.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_6.scala @@ -92,7 +92,7 @@ object visualization_6 extends App { val (vehiclesEvents, _) = Reader.readWithFilter(beamEventsFilePath, filter) val (events, typeToId) = Reader.transformPathTraversals(vehiclesEvents, vehicleId, vehicleType) - Writer.writeViaEventsQueue[ViaEvent](events, _.toXml.toString, viaEventsFile) + Writer.writeViaEventsQueue(events, _.toXml.toString, viaEventsFile) Writer.writeViaIdFile(typeToId, viaIdsFile) } } diff --git a/src/test/scala/beam/utils/beam_to_matsim/io/WriterTest.scala b/src/test/scala/beam/utils/beam_to_matsim/io/WriterTest.scala new file mode 100644 index 00000000000..c248737bd65 --- /dev/null +++ b/src/test/scala/beam/utils/beam_to_matsim/io/WriterTest.scala @@ -0,0 +1,63 @@ +package beam.utils.beam_to_matsim.io + +import beam.utils.beam_to_matsim.via_event.{ViaEvent, ViaEventsCollection} +import org.scalatest.funsuite.AnyFunSuite +import org.scalatest.matchers.should.Matchers + +import scala.collection.mutable +import scala.xml.Elem + +class WriterTest extends AnyFunSuite with Matchers { + + case class VEvent(var time: Double) extends ViaEvent with Ordered[VEvent] { + + override val link: Int = 0 + + override def toXml: Elem = ??? + + override def toXmlString: String = ??? + + override def compare(that: VEvent): Int = time.compare(that.time) + } + + def resultAndDuration[T](func: => T): (T, Double) = { + val t1 = System.nanoTime + val result = func + val duration = (System.nanoTime - t1) / 1e9d + (result, duration) + } + + def sortingPriorityQueue(unsortedSeq: Seq[ViaEvent]): Seq[ViaEvent] = { + val queue: mutable.PriorityQueue[ViaEvent] = mutable.PriorityQueue()((e1, e2) => e2.time.compare(e1.time)) + unsortedSeq.foreach { line => queue.enqueue(line) } + + val sortedSeq = mutable.ArrayBuffer.empty[ViaEvent] + while (queue.nonEmpty) { + sortedSeq += queue.dequeue() + } + sortedSeq + } + + def sortingJavaArrayParallel(unsortedSeq: Seq[ViaEvent]): Seq[ViaEvent] = { + val eventsCollection = new ViaEventsCollection() + unsortedSeq.foreach(eventsCollection.put) + eventsCollection.getSortedEvents + } + + test("testWriteViaEventsQueue") { + val experimentLen = 2 * 1000000 + def getUnsortedSeq: Seq[ViaEvent] = (0 until experimentLen).map { _ => VEvent(math.random()) } + val unsorted1 = getUnsortedSeq + val unsorted2 = getUnsortedSeq + + val (sortedSeq1, duration1) = resultAndDuration { sortingPriorityQueue(unsorted1) } + val (sortedSeq2, duration2) = resultAndDuration { sortingJavaArrayParallel(unsorted2) } + + sortedSeq1.size shouldBe experimentLen + sortedSeq2.size shouldBe experimentLen + sortedSeq1.map(_.time) shouldBe sorted + sortedSeq2.map(_.time) shouldBe sorted + duration2 * 4 should be < duration1 + } + +} From bed07ab9a3488db29336632e29ffee8f5ea398f7 Mon Sep 17 00:00:00 2001 From: Nikolay Ilyin Date: Tue, 19 Apr 2022 23:19:45 +0300 Subject: [PATCH 05/25] bugfix --- .../utils/beam_to_matsim/EventsByVehicleMode.scala | 12 ++++++------ .../scala/beam/utils/beam_to_matsim/io/Reader.scala | 2 +- .../scala/beam/utils/beam_to_matsim/io/Writer.scala | 2 +- .../via_event/ViaEventsCollection.scala | 2 ++ 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/scala/beam/utils/beam_to_matsim/EventsByVehicleMode.scala b/src/main/scala/beam/utils/beam_to_matsim/EventsByVehicleMode.scala index e51a174ba18..af97c26b432 100644 --- a/src/main/scala/beam/utils/beam_to_matsim/EventsByVehicleMode.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/EventsByVehicleMode.scala @@ -14,9 +14,9 @@ object EventsByVehicleMode extends App { // gradle execute -PmainClass=beam.utils.beamToVia.EventsByVehicleMode -PappArgs="['D:/Work/BEAM/history/visualizations/v35.it3.events.csv', 'D:/Work/BEAM/_tmp/output.via.xml', 'car,bus', '0.5', 'D:/Work/BEAM/history/visualizations/physSimNetwork.xml', '548966', '4179000', '500']" -PmaxRAM=16g val inputArgs1 = Seq( // Events file path may be in csv or xml format. Does not work with archives. - "D:/Work/BEAM/history/visualizations/v33.0.events.csv", + "/mnt/data/work/beam/beam-production/output/sf-light/sf-light-1k-xml__2022-04-06_22-49-06_rub/ITERS/it.0/0.events.csv.gz", // output file path - "D:/Work/BEAM/_tmp/output.via.xml", + "/mnt/data/work/beam/beam-production/output/sf-light/sf-light-1k-xml__2022-04-06_22-49-06_rub/ITERS/it.0/0.events.via.xml", // list of vehicle modes, case insensitive "car,bus", // 1 means 100% @@ -30,18 +30,18 @@ object EventsByVehicleMode extends App { ) // gradle execute -PmainClass=beam.utils.beamToVia.EventsByVehicleMode -PappArgs="['D:/Work/BEAM/history/visualizations/v33.0.events.csv', 'D:/Work/BEAM/_tmp/output.via.xml', 'car,bus', '1']" -PmaxRAM=16g - val nputArgs2 = Seq( + val inputArgs2 = Seq( // Events file path may be in csv or xml format. Does not work with archives. - "D:/Work/BEAM/history/visualizations/v33.0.events.csv", //v35.it3.events.csv", // + "/mnt/data/work/beam/beam-production/output/sf-light/sf-light-1k-xml__2022-04-19_22-14-35_ahm/ITERS/it.0/0.events.csv", // output file path - "D:/Work/BEAM/_tmp/output.via.xml", + "/mnt/data/work/beam/beam-production/output/sf-light/sf-light-1k-xml__2022-04-19_22-14-35_ahm/ITERS/it.0/0.events.via.xml", // list of vehicle modes, case insensitive "car,bus", // 1 means 100% "1" ) - val inputArgs = args // inputArgs2 + val inputArgs = inputArgs2 if (inputArgs.length == 4) { val eventsFile = inputArgs.head diff --git a/src/main/scala/beam/utils/beam_to_matsim/io/Reader.scala b/src/main/scala/beam/utils/beam_to_matsim/io/Reader.scala index 9500d6a394b..d279d35b317 100644 --- a/src/main/scala/beam/utils/beam_to_matsim/io/Reader.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/io/Reader.scala @@ -26,7 +26,7 @@ object Reader { // fix overlapping of path traversal events for vehicle def pteOverlappingFix(pteSeqRaw: Seq[BeamPathTraversal]): Unit = { - val pteSeq = pteSeqRaw.filter(pte => pte.linkTravelTime.isEmpty) + val pteSeq = pteSeqRaw.filter(pte => pte.linkTravelTime.nonEmpty) @SuppressWarnings(Array("UnsafeTraversableMethods")) val pteSeqHead = pteSeq.head pteSeq.drop(1).foldLeft(pteSeqHead) { diff --git a/src/main/scala/beam/utils/beam_to_matsim/io/Writer.scala b/src/main/scala/beam/utils/beam_to_matsim/io/Writer.scala index e0750717da6..cfd57b45694 100644 --- a/src/main/scala/beam/utils/beam_to_matsim/io/Writer.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/io/Writer.scala @@ -45,7 +45,7 @@ object Writer { FileUtils.using(new PrintWriter(new File(outputPath))) { pw => pw.println("\n") - val sortedEvents = eventsCollection.getSortedEvents() + val sortedEvents = eventsCollection.getSortedEvents sortedEvents.foreach { entry => progress.step() diff --git a/src/main/scala/beam/utils/beam_to_matsim/via_event/ViaEventsCollection.scala b/src/main/scala/beam/utils/beam_to_matsim/via_event/ViaEventsCollection.scala index 1b2ca4526a9..d6aa780043e 100644 --- a/src/main/scala/beam/utils/beam_to_matsim/via_event/ViaEventsCollection.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/via_event/ViaEventsCollection.scala @@ -16,6 +16,8 @@ class ViaEventsCollection { java.util.Arrays.parallelSort(arrayToSort, comparator) arrayToSort } + def put(event: ViaEvent): Unit = unsortedEvents.append(event) + def size: Int = unsortedEvents.length } From 606ddaa1eda94edb30bb9830370408f3f7e51457 Mon Sep 17 00:00:00 2001 From: Nikolay Ilyin Date: Tue, 19 Apr 2022 23:33:37 +0300 Subject: [PATCH 06/25] args instead of debug --- .../scala/beam/utils/beam_to_matsim/EventsByVehicleMode.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/beam/utils/beam_to_matsim/EventsByVehicleMode.scala b/src/main/scala/beam/utils/beam_to_matsim/EventsByVehicleMode.scala index af97c26b432..12163f03ad5 100644 --- a/src/main/scala/beam/utils/beam_to_matsim/EventsByVehicleMode.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/EventsByVehicleMode.scala @@ -41,7 +41,7 @@ object EventsByVehicleMode extends App { "1" ) - val inputArgs = inputArgs2 + val inputArgs = args // inputArgs2 if (inputArgs.length == 4) { val eventsFile = inputArgs.head From 28ad87120bc105ba3e1f0284a2fef2fc98fc3013 Mon Sep 17 00:00:00 2001 From: Nikolay Ilyin Date: Wed, 20 Apr 2022 14:22:13 +0300 Subject: [PATCH 07/25] various bugfixes --- .../beam_to_matsim/EventsByVehicleMode.scala | 8 ++-- .../beam_to_matsim/events/BeamActivity.scala | 2 +- .../events/BeamModeChoice.scala | 2 +- .../events/BeamPathTraversal.scala | 6 +-- .../beam_to_matsim/io/ConsoleProgress.scala | 2 +- .../beam/utils/beam_to_matsim/io/Reader.scala | 44 +++++++++++-------- .../beam/utils/beam_to_matsim/io/Writer.scala | 29 +++--------- .../via_event/ViaActivity.scala | 4 +- .../via_event/ViaPersonArrivalEvent.scala | 2 +- .../via_event/ViaPersonDepartureEvent.scala | 2 +- .../via_event/ViaTraverseLinkEvent.scala | 5 ++- .../visualization/via/visualization_11.scala | 2 +- .../visualization/via/visualization_12.scala | 8 ++-- .../via/visualization_20_24.scala | 2 +- .../via/visualization_33_34.scala | 2 +- .../visualization/via/visualization_35.scala | 2 +- .../via/visualization_3_4_5.scala | 2 +- .../visualization/via/visualization_6.scala | 2 +- .../visualization/via/visualization_9.scala | 10 ++--- 19 files changed, 61 insertions(+), 75 deletions(-) diff --git a/src/main/scala/beam/utils/beam_to_matsim/EventsByVehicleMode.scala b/src/main/scala/beam/utils/beam_to_matsim/EventsByVehicleMode.scala index 12163f03ad5..98b58d5e484 100644 --- a/src/main/scala/beam/utils/beam_to_matsim/EventsByVehicleMode.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/EventsByVehicleMode.scala @@ -32,16 +32,16 @@ object EventsByVehicleMode extends App { // gradle execute -PmainClass=beam.utils.beamToVia.EventsByVehicleMode -PappArgs="['D:/Work/BEAM/history/visualizations/v33.0.events.csv', 'D:/Work/BEAM/_tmp/output.via.xml', 'car,bus', '1']" -PmaxRAM=16g val inputArgs2 = Seq( // Events file path may be in csv or xml format. Does not work with archives. - "/mnt/data/work/beam/beam-production/output/sf-light/sf-light-1k-xml__2022-04-19_22-14-35_ahm/ITERS/it.0/0.events.csv", + "/mnt/data/work/beam/beam-production/freight-base-2018-60k__2022-04-19_04-36-11_rrq.0.events.1000000.csv", // output file path - "/mnt/data/work/beam/beam-production/output/sf-light/sf-light-1k-xml__2022-04-19_22-14-35_ahm/ITERS/it.0/0.events.via.xml", + "/mnt/data/work/beam/beam-production/freight-base-2018-60k__2022-04-19_04-36-11_rrq.0.events.1000000.via.xml", // list of vehicle modes, case insensitive "car,bus", // 1 means 100% "1" ) - val inputArgs = args // inputArgs2 + val inputArgs = inputArgs2 if (inputArgs.length == 4) { val eventsFile = inputArgs.head @@ -98,7 +98,7 @@ object EventsByVehicleMode extends App { val (vehiclesEvents, _) = Reader.readWithFilter(eventsFile, filter) val (events, typeToId) = Reader.transformPathTraversals(vehiclesEvents, vehicleId, vehicleType) - Writer.writeViaEventsQueue(events, _.toXmlString, outputFile) + Writer.writeViaEventsCollection(events, _.toXmlString, outputFile) Writer.writeViaIdFile(typeToId, outputFile + ".ids.txt") } diff --git a/src/main/scala/beam/utils/beam_to_matsim/events/BeamActivity.scala b/src/main/scala/beam/utils/beam_to_matsim/events/BeamActivity.scala index 070b25a8e2b..571b9db8ea8 100644 --- a/src/main/scala/beam/utils/beam_to_matsim/events/BeamActivity.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/events/BeamActivity.scala @@ -41,7 +41,7 @@ object BeamActivity { val time = genericEvent.getTime val personId: String = attr(ATTRIBUTE_PERSON_ID) - val linkId: Int = attr(ATTRIBUTE_LINK_ID).toInt + val linkId: Int = attr(ATTRIBUTE_LINK_ID).toDouble.toInt val activityType = attr(ATTRIBUTE_ACTTYPE) new BeamActivity(time, personId, linkId, activityType) diff --git a/src/main/scala/beam/utils/beam_to_matsim/events/BeamModeChoice.scala b/src/main/scala/beam/utils/beam_to_matsim/events/BeamModeChoice.scala index d81e9a44142..93341a4aae9 100644 --- a/src/main/scala/beam/utils/beam_to_matsim/events/BeamModeChoice.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/events/BeamModeChoice.scala @@ -17,7 +17,7 @@ object BeamModeChoice { val time = genericEvent.getTime val personId: String = attr(ATTRIBUTE_PERSON_ID) - val linkId: Int = attr(ATTRIBUTE_LINK_ID).toInt + val linkId: Int = attr(ATTRIBUTE_LINK_ID).toDouble.toInt val mode = attr(ATTRIBUTE_MODE) new BeamModeChoice(time, personId, linkId, mode) diff --git a/src/main/scala/beam/utils/beam_to_matsim/events/BeamPathTraversal.scala b/src/main/scala/beam/utils/beam_to_matsim/events/BeamPathTraversal.scala index f51ba4d139d..11fb4e961b3 100644 --- a/src/main/scala/beam/utils/beam_to_matsim/events/BeamPathTraversal.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/events/BeamPathTraversal.scala @@ -48,9 +48,9 @@ object BeamPathTraversal { val vehicleId: String = attr(ATTRIBUTE_VEHICLE_ID) val driverId: String = attr(ATTRIBUTE_DRIVER_ID) val vehicleType: String = attr(ATTRIBUTE_VEHICLE_TYPE) - val numberOfPassengers: Int = attr(ATTRIBUTE_NUM_PASS).toInt - val time: Int = attr(ATTRIBUTE_DEPARTURE_TIME).toInt - var arrivalTime: Int = attr(ATTRIBUTE_ARRIVAL_TIME).toInt + val numberOfPassengers: Int = attr(ATTRIBUTE_NUM_PASS).toDouble.toInt + val time: Int = attr(ATTRIBUTE_DEPARTURE_TIME).toDouble.toInt + var arrivalTime: Int = attr(ATTRIBUTE_ARRIVAL_TIME).toDouble.toInt val linkIdsAsStr = Option(attr.getOrElse(ATTRIBUTE_LINK_IDS, "")) val linkIds: Seq[Int] = linkIdsAsStr match { diff --git a/src/main/scala/beam/utils/beam_to_matsim/io/ConsoleProgress.scala b/src/main/scala/beam/utils/beam_to_matsim/io/ConsoleProgress.scala index ba7653859d6..7ee63509c15 100644 --- a/src/main/scala/beam/utils/beam_to_matsim/io/ConsoleProgress.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/io/ConsoleProgress.scala @@ -22,7 +22,7 @@ class ConsoleProgress(message: String, maxSteps: Int, percentageToWrite: Int = 1 def print(message: String): Unit = Console.println(s"\t$message") def write(): Unit = { - val percentage = currentStep / onePercent + val percentage = currentStep / math.max(onePercent, 1) if (percentage < 100) { print(s"$percentage% $message") } diff --git a/src/main/scala/beam/utils/beam_to_matsim/io/Reader.scala b/src/main/scala/beam/utils/beam_to_matsim/io/Reader.scala index d279d35b317..df492782225 100644 --- a/src/main/scala/beam/utils/beam_to_matsim/io/Reader.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/io/Reader.scala @@ -2,7 +2,7 @@ package beam.utils.beam_to_matsim.io import beam.utils.beam_to_matsim.events.{BeamActivityEnd, BeamActivityStart, BeamModeChoice, BeamPathTraversal} import beam.utils.beam_to_matsim.events_filter.{MutableSamplingFilter, PersonEvents, VehicleTrip} -import beam.utils.beam_to_matsim.via_event.{ViaEventsCollection, _} +import beam.utils.beam_to_matsim.via_event._ import scala.collection.mutable @@ -27,26 +27,32 @@ object Reader { // fix overlapping of path traversal events for vehicle def pteOverlappingFix(pteSeqRaw: Seq[BeamPathTraversal]): Unit = { val pteSeq = pteSeqRaw.filter(pte => pte.linkTravelTime.nonEmpty) - @SuppressWarnings(Array("UnsafeTraversableMethods")) - val pteSeqHead = pteSeq.head - pteSeq.drop(1).foldLeft(pteSeqHead) { - case (prevPTE, currPTE) if prevPTE.linkIds.nonEmpty && currPTE.linkIds.nonEmpty => - // if they overlap each other in case of time - val timeDiff = currPTE.time - prevPTE.arrivalTime - if (timeDiff < 0) prevPTE.adjustTime(timeDiff) - - // if they overlap each other in case of travel links - if (prevPTE.linkIds.lastOption == currPTE.linkIds.headOption) { - currPTE.removeHeadLinkFromTrip() - @SuppressWarnings(Array("UnsafeTraversableMethods")) - val removedLinkTime = currPTE.linkTravelTime.head - if (currPTE.linkIds.nonEmpty) currPTE.adjustTime(removedLinkTime) - else prevPTE.adjustTime(removedLinkTime) - } + val maybePteSeqHead = pteSeq.headOption + maybePteSeqHead match { + case Some(pteSeqHead) => + pteSeq.drop(1).foldLeft(pteSeqHead) { + case (prevPTE, currPTE) if prevPTE.linkIds.nonEmpty && currPTE.linkIds.nonEmpty => + // if they overlap each other in case of time + val timeDiff = currPTE.time - prevPTE.arrivalTime + if (timeDiff < 0) prevPTE.adjustTime(timeDiff) + + // if they overlap each other in case of travel links + if (prevPTE.linkIds.lastOption == currPTE.linkIds.headOption) { + currPTE.removeHeadLinkFromTrip() + + val maybeRemovedLinkTime = currPTE.linkTravelTime.headOption + maybeRemovedLinkTime match { + case Some(removedLinkTime) if currPTE.linkIds.nonEmpty => currPTE.adjustTime(removedLinkTime) + case Some(removedLinkTime) => prevPTE.adjustTime(removedLinkTime) + case None => + } + } - currPTE + currPTE - case (_, pte) => pte + case (_, pte) => pte + } + case None => } } diff --git a/src/main/scala/beam/utils/beam_to_matsim/io/Writer.scala b/src/main/scala/beam/utils/beam_to_matsim/io/Writer.scala index cfd57b45694..50e7c29f9b2 100644 --- a/src/main/scala/beam/utils/beam_to_matsim/io/Writer.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/io/Writer.scala @@ -1,9 +1,9 @@ package beam.utils.beam_to_matsim.io -import java.io.{File, PrintWriter} import beam.utils.FileUtils import beam.utils.beam_to_matsim.via_event.{ViaEvent, ViaEventsCollection} +import java.io.{File, PrintWriter} import scala.collection.mutable object Writer { @@ -14,39 +14,20 @@ object Writer { } } - def writeViaEventsQueue[T](queue: mutable.PriorityQueue[T], transform: T => String, outputPath: String): Unit = { - val eventsCount = queue.size - Console.println(s"started writing $eventsCount events ...") - val progress = new ConsoleProgress("evenst written", eventsCount, 5) - FileUtils.using(new PrintWriter(new File(outputPath))) { pw => - pw.println("\n") - while (queue.nonEmpty) { - progress.step() - val entry = queue.dequeue() - pw.println(transform(entry)) - } - pw.println("") - } - - progress.finish() - - Console.println("via events written into " + outputPath) - } - - def writeViaEventsQueue( + def writeViaEventsCollection( eventsCollection: ViaEventsCollection, transform: ViaEvent => String, outputPath: String ): Unit = { val eventsCount = eventsCollection.size + Console.println(s"sorting $eventsCount events ...") + val sortedEvents = eventsCollection.getSortedEvents + Console.println(s"started writing $eventsCount events ...") val progress = new ConsoleProgress("evenst written", eventsCount, 5) - FileUtils.using(new PrintWriter(new File(outputPath))) { pw => pw.println("\n") - val sortedEvents = eventsCollection.getSortedEvents - sortedEvents.foreach { entry => progress.step() pw.println(transform(entry)) diff --git a/src/main/scala/beam/utils/beam_to_matsim/via_event/ViaActivity.scala b/src/main/scala/beam/utils/beam_to_matsim/via_event/ViaActivity.scala index 63be911c9c7..0a97b5daa41 100644 --- a/src/main/scala/beam/utils/beam_to_matsim/via_event/ViaActivity.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/via_event/ViaActivity.scala @@ -27,9 +27,9 @@ case class ViaActivity( def toXmlString: String = eventType match { case ActionStart => - s"""""" + s"""""" case ActionEnd => - s"""""" + s"""""" } def toXml: scala.xml.Elem = diff --git a/src/main/scala/beam/utils/beam_to_matsim/via_event/ViaPersonArrivalEvent.scala b/src/main/scala/beam/utils/beam_to_matsim/via_event/ViaPersonArrivalEvent.scala index d8a8d977fd1..40d33f62583 100644 --- a/src/main/scala/beam/utils/beam_to_matsim/via_event/ViaPersonArrivalEvent.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/via_event/ViaPersonArrivalEvent.scala @@ -3,7 +3,7 @@ package beam.utils.beam_to_matsim.via_event case class ViaPersonArrivalEvent(var time: Double, person: String, link: Int) extends ViaEvent { def toXmlString: String = - s"""""" + s"""""" def toXml: scala.xml.Elem = diff --git a/src/main/scala/beam/utils/beam_to_matsim/via_event/ViaPersonDepartureEvent.scala b/src/main/scala/beam/utils/beam_to_matsim/via_event/ViaPersonDepartureEvent.scala index 3e8e2b9afd8..a9288920361 100644 --- a/src/main/scala/beam/utils/beam_to_matsim/via_event/ViaPersonDepartureEvent.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/via_event/ViaPersonDepartureEvent.scala @@ -3,7 +3,7 @@ package beam.utils.beam_to_matsim.via_event case class ViaPersonDepartureEvent(var time: Double, person: String, link: Int) extends ViaEvent { def toXmlString: String = - s"""""" + s"""""" def toXml: scala.xml.Elem = diff --git a/src/main/scala/beam/utils/beam_to_matsim/via_event/ViaTraverseLinkEvent.scala b/src/main/scala/beam/utils/beam_to_matsim/via_event/ViaTraverseLinkEvent.scala index e244d9b6fb3..8650b3b95fd 100644 --- a/src/main/scala/beam/utils/beam_to_matsim/via_event/ViaTraverseLinkEvent.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/via_event/ViaTraverseLinkEvent.scala @@ -18,8 +18,9 @@ case class ViaTraverseLinkEvent(var time: Double, vehicle: String, eventType: Vi def toXmlString: String = eventType match { - case EnteredLink => s"""""" - case LeftLink => s"""""" + case EnteredLink => + s"""""" + case LeftLink => s"""""" } def toXml: scala.xml.Elem = diff --git a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_11.scala b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_11.scala index 9ef03f87d7a..0f0dffcbdff 100755 --- a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_11.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_11.scala @@ -66,6 +66,6 @@ object visualization_11 extends App { val (vehiclesEvents, _) = Reader.readWithFilter(beamEventsFilePath, filter) val (events, typeToId) = Reader.transformPathTraversals(vehiclesEvents, vehicleId, vehicleType) - Writer.writeViaEventsQueue(events, _.toXml.toString, viaEventsFile) + Writer.writeViaEventsCollection(events, _.toXml.toString, viaEventsFile) Writer.writeViaIdFile(typeToId, viaIdsFile) } diff --git a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_12.scala b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_12.scala index 0f31cb937e4..14298170704 100755 --- a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_12.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_12.scala @@ -2,7 +2,7 @@ package beam.utils.beam_to_matsim.visualization.via import beam.utils.beam_to_matsim.events_filter.{MutablePopulationFilter, MutableSamplingFilter, PopulationSample} import beam.utils.beam_to_matsim.io.{Reader, Writer} -import beam.utils.beam_to_matsim.via_event.ViaEvent +import beam.utils.beam_to_matsim.via_event.{ViaEvent, ViaEventsCollection} import java.io.File import java.nio.file.Files @@ -27,10 +27,10 @@ object visualization_12 extends App { val (vehiclesEvents, personsEvents) = Reader.readWithFilter(beamEventsFilePath, filter) - val events = mutable.PriorityQueue.empty[ViaEvent]((e1, e2) => e2.time.compare(e1.time)) + val eventsCollection = new ViaEventsCollection() val (activities, activityToCnt) = Reader.transformActivities(personsEvents) - activities.foreach(events.enqueue(_)) + activities.foreach(eventsCollection.put) - Writer.writeViaEventsQueue[ViaEvent](events, _.toXml.toString, viaEventsFile) + Writer.writeViaEventsCollection(eventsCollection, _.toXml.toString, viaEventsFile) Writer.writeViaActivities(activityToCnt, viaModesFile) } diff --git a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_20_24.scala b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_20_24.scala index 089227566df..652149a57d6 100755 --- a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_20_24.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_20_24.scala @@ -30,7 +30,7 @@ object visualization_20_24 extends App { val (activities, activityToCnt) = Reader.transformActivities(personsEvents) activities.foreach(events.put) - Writer.writeViaEventsQueue(events, _.toXml.toString, viaEventsFile) + Writer.writeViaEventsCollection(events, _.toXml.toString, viaEventsFile) Writer.writeViaActivities(activityToCnt, viaActivitiesFile) Writer.writeViaModes(modeToCnt, viaModesFile) diff --git a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_33_34.scala b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_33_34.scala index d9b15c8285c..aa15c7ee782 100755 --- a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_33_34.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_33_34.scala @@ -46,6 +46,6 @@ object visualization_33_34 extends App { val (vehiclesEvents, _) = Reader.readWithFilter(beamEventsFilePath, MutableVehiclesFilter(Selector)) val (events, typeToId) = Reader.transformPathTraversals(vehiclesEvents, vehicleId, vehicleType) - Writer.writeViaEventsQueue(events, _.toXml.toString, viaEventsFile) + Writer.writeViaEventsCollection(events, _.toXml.toString, viaEventsFile) Writer.writeViaIdFile(typeToId, viaIdsFile) } diff --git a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_35.scala b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_35.scala index e165cae07f5..c7a4aeed907 100755 --- a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_35.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_35.scala @@ -71,7 +71,7 @@ object visualization_35 extends App { val (events, typeToId) = Reader.transformPathTraversals(eventsWithAlternatives, vehicleId, vehicleType) - Writer.writeViaEventsQueue(events, _.toXml.toString, viaEventsFile) + Writer.writeViaEventsCollection(events, _.toXml.toString, viaEventsFile) Writer.writeViaIdFile(typeToId, viaIdFile) } diff --git a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_3_4_5.scala b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_3_4_5.scala index a85eda221de..86dc81aa1f9 100755 --- a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_3_4_5.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_3_4_5.scala @@ -61,6 +61,6 @@ object visualization_3_4_5 extends App { val (vehiclesEvents, _) = Reader.readWithFilter(beamEventsFilePath, filter) val (events, typeToId) = Reader.transformPathTraversals(vehiclesEvents, vehicleId, vehicleType) - Writer.writeViaEventsQueue(events, _.toXml.toString, viaEventsFile) + Writer.writeViaEventsCollection(events, _.toXml.toString, viaEventsFile) Writer.writeViaIdFile(typeToId, viaIdsFile) } diff --git a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_6.scala b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_6.scala index 0ff74b88aeb..ed4518e6128 100755 --- a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_6.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_6.scala @@ -92,7 +92,7 @@ object visualization_6 extends App { val (vehiclesEvents, _) = Reader.readWithFilter(beamEventsFilePath, filter) val (events, typeToId) = Reader.transformPathTraversals(vehiclesEvents, vehicleId, vehicleType) - Writer.writeViaEventsQueue(events, _.toXml.toString, viaEventsFile) + Writer.writeViaEventsCollection(events, _.toXml.toString, viaEventsFile) Writer.writeViaIdFile(typeToId, viaIdsFile) } } diff --git a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_9.scala b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_9.scala index 707e6a1aac9..922f1d830b9 100755 --- a/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_9.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/visualization/via/visualization_9.scala @@ -3,9 +3,7 @@ package beam.utils.beam_to_matsim.visualization.via import beam.utils.beam_to_matsim.events.BeamPathTraversal import beam.utils.beam_to_matsim.events_filter.{MutablePopulationFilter, MutableSamplingFilter, PopulationSample} import beam.utils.beam_to_matsim.io.{HashSetReader, Reader, Writer} -import beam.utils.beam_to_matsim.via_event.ViaEvent - -import scala.collection.mutable +import beam.utils.beam_to_matsim.via_event.ViaEventsCollection object visualization_9 extends App { val personsInCircleFilePath = "D:/Work/BEAM/visualizations/v2.it20.events.bridge_cap_5000.half_in_SF.persons.txt" @@ -35,11 +33,11 @@ object visualization_9 extends App { val (vehiclesEvents, personsEvents) = Reader.readWithFilter(beamEventsFilePath, filter) //val (events, typeToId) = EventsProcessor.transformPathTraversals(vehiclesEvents, vehicleId, vehicleType) - val events = mutable.PriorityQueue.empty[ViaEvent]((e1, e2) => e2.time.compare(e1.time)) + val eventsCollection = new ViaEventsCollection() val (modeChoiceEvents, modeToCnt) = Reader.transformModeChoices(personsEvents) - modeChoiceEvents.foreach(events.enqueue(_)) + modeChoiceEvents.foreach(eventsCollection.put) - Writer.writeViaEventsQueue[ViaEvent](events, _.toXml.toString, viaEventsFile) + Writer.writeViaEventsCollection(eventsCollection, _.toXml.toString, viaEventsFile) //Writer.writeViaIdFile(typeToId, viaIdsFile) Writer.writeViaModes(modeToCnt, viaModesFile) } From 8c1efe3d331b3eed3cdc5cdb766eb8da9af74dbb Mon Sep 17 00:00:00 2001 From: Nikolay Ilyin Date: Wed, 20 Apr 2022 15:28:19 +0300 Subject: [PATCH 08/25] using args --- .../scala/beam/utils/beam_to_matsim/EventsByVehicleMode.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/beam/utils/beam_to_matsim/EventsByVehicleMode.scala b/src/main/scala/beam/utils/beam_to_matsim/EventsByVehicleMode.scala index 98b58d5e484..7d28f29b977 100644 --- a/src/main/scala/beam/utils/beam_to_matsim/EventsByVehicleMode.scala +++ b/src/main/scala/beam/utils/beam_to_matsim/EventsByVehicleMode.scala @@ -41,7 +41,7 @@ object EventsByVehicleMode extends App { "1" ) - val inputArgs = inputArgs2 + val inputArgs = args if (inputArgs.length == 4) { val eventsFile = inputArgs.head From cd28695a6237c65fe6deae81b6adb46a36495fa0 Mon Sep 17 00:00:00 2001 From: Dmitry Openkov Date: Fri, 22 Apr 2022 18:58:47 +0300 Subject: [PATCH 09/25] Parking search new algo --- src/main/resources/beam-template.conf | 2 + .../agents/household/HouseholdActor.scala | 14 ++- .../household/HouseholdFleetManager.scala | 27 +++-- .../DefaultRideHailDepotParkingManager.scala | 4 + .../RideHailDepotParkingManager.scala | 2 +- .../agents/vehicles/VehicleManager.scala | 4 +- .../infrastructure/ChargingFunctions.scala | 4 + .../infrastructure/ChargingNetwork.scala | 2 + .../DefaultRidehailFunctions.scala | 4 + .../HierarchicalParkingManager.scala | 8 +- .../InfrastructureFunctions.scala | 28 ++++- .../ParallelParkingManager.scala | 6 + .../infrastructure/ParkingFunctions.scala | 12 +- .../ParkingManagerBenchmark.scala | 31 ++--- .../infrastructure/ZonalParkingManager.scala | 8 ++ .../parking/ParkingNetwork.scala | 4 +- .../infrastructure/parking/ParkingZone.scala | 9 +- .../parking/ParkingZoneSearch.scala | 109 ++++++++++++++++-- .../scala/beam/sim/config/BeamConfig.scala | 18 +-- src/main/scala/beam/utils/MathUtils.scala | 34 ++++++ .../ParallelParkingManagerSpec.scala | 12 +- .../ZonalParkingManagerSpec.scala | 20 ++-- src/test/scala/beam/utils/MathUtilsSpec.scala | 49 ++++++++ test/input/sf-light/taz-parking.csv | 4 +- 24 files changed, 327 insertions(+), 88 deletions(-) diff --git a/src/main/resources/beam-template.conf b/src/main/resources/beam-template.conf index 1b5b890d40d..ec2e7f4ef05 100755 --- a/src/main/resources/beam-template.conf +++ b/src/main/resources/beam-template.conf @@ -168,6 +168,8 @@ beam.agentsim.agents.parking.rangeAnxietyBuffer = "double | 20000.0" # if our re beam.agentsim.agents.parking.minSearchRadius = "double | 250.00" # something small enough that, on average, we see 2 orders of magnitude of samples at most beam.agentsim.agents.parking.maxSearchRadius = "double | 8046.72" # something large enough that we do not strand our drivers in an oasis beam.agentsim.agents.parking.searchMaxDistanceRelativeToEllipseFoci = "double | 4.0" # something large enough that we do not travel longer than the actual distance to destination +beam.agentsim.agents.parking.fractionOfSameTypeZones = "double | 0.5" +beam.agentsim.agents.parking.minNumberOfSameTypeZones = "int | 10" #TAZ params beam.agentsim.taz.filePath = ${beam.inputDirectory}"/taz-centers.csv" diff --git a/src/main/scala/beam/agentsim/agents/household/HouseholdActor.scala b/src/main/scala/beam/agentsim/agents/household/HouseholdActor.scala index a254d417868..37f09f1c98e 100755 --- a/src/main/scala/beam/agentsim/agents/household/HouseholdActor.scala +++ b/src/main/scala/beam/agentsim/agents/household/HouseholdActor.scala @@ -48,6 +48,7 @@ import org.matsim.households import org.matsim.households.Household import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicReference import scala.collection.mutable import scala.concurrent.{ExecutionContext, Future} import scala.jdk.CollectionConverters.collectionAsScalaIterableConverter @@ -529,7 +530,13 @@ object HouseholdActor { veh.setManager(Some(self)) for { ParkingInquiryResponse(stall, _, _) <- parkingManager ? ParkingInquiry - .init(veh.spaceTime, "init", triggerId = triggerId) + .init( + veh.spaceTime, + "init", + VehicleManager.getReservedFor(veh.vehicleManagerId.get()).get, + Some(veh), + triggerId = triggerId + ) } { veh.useParkingStall(stall) veh.spaceTime = SpaceTime(stall.locationUTM.getX, stall.locationUTM.getY, 0) @@ -612,10 +619,13 @@ object HouseholdActor { whenWhere: SpaceTime, manager: ActorRef ): BeamVehicle = { + val vehicleManagerId = + VehicleManager.createOrGetReservedFor(household.getId.toString, VehicleManager.TypeEnum.Household).managerId val vehicle = new BeamVehicle( Id.createVehicleId(personId.toString + "-emergency-" + vehicleIndex), new Powertrain(vehicleType.primaryFuelConsumptionInJoulePerMeter), - vehicleType + vehicleType, + new AtomicReference[Id[VehicleManager]](vehicleManagerId) ) vehicle.initializeFuelLevelsFromUniformDistribution( beamScenario.beamConfig.beam.agentsim.agents.vehicles.meanPrivateVehicleStartingSOC diff --git a/src/main/scala/beam/agentsim/agents/household/HouseholdFleetManager.scala b/src/main/scala/beam/agentsim/agents/household/HouseholdFleetManager.scala index 98aa94799d1..6c8ace92bdb 100644 --- a/src/main/scala/beam/agentsim/agents/household/HouseholdFleetManager.scala +++ b/src/main/scala/beam/agentsim/agents/household/HouseholdFleetManager.scala @@ -10,7 +10,7 @@ import beam.agentsim.agents.InitializeTrigger import beam.agentsim.agents.household.HouseholdActor._ import beam.agentsim.agents.household.HouseholdFleetManager.ResolvedParkingResponses import beam.agentsim.agents.modalbehaviors.DrivesVehicle.ActualVehicle -import beam.agentsim.agents.vehicles.BeamVehicle +import beam.agentsim.agents.vehicles.{BeamVehicle, VehicleManager} import beam.agentsim.events.SpaceTime import beam.agentsim.infrastructure.{ParkingInquiry, ParkingInquiryResponse} import beam.agentsim.scheduler.BeamAgentScheduler.CompletionNotice @@ -59,16 +59,19 @@ class HouseholdFleetManager( case TriggerWithId(InitializeTrigger(_), triggerId) => triggerSender = Some(sender()) - val listOfFutures: List[Future[(Id[BeamVehicle], ParkingInquiryResponse)]] = vehicles.toList.map { case (id, _) => - (parkingManager ? ParkingInquiry.init( - SpaceTime(homeCoord, 0), - "init", - triggerId = triggerId - )) - .mapTo[ParkingInquiryResponse] - .map { r => - (id, r) - } + val listOfFutures: List[Future[(Id[BeamVehicle], ParkingInquiryResponse)]] = vehicles.toList.map { + case (id, veh) => + (parkingManager ? ParkingInquiry.init( + SpaceTime(homeCoord, 0), + "init", + VehicleManager.getReservedFor(veh.vehicleManagerId.get()).get, + Some(veh), + triggerId = triggerId + )) + .mapTo[ParkingInquiryResponse] + .map { r => + (id, r) + } } val futureOfList = Future.sequence(listOfFutures) val response = futureOfList.map(ResolvedParkingResponses(triggerId, _)) @@ -171,6 +174,8 @@ class HouseholdFleetManager( val responseFuture = parkingManager ? ParkingInquiry.init( inquiry.whereWhen, "wherever", + VehicleManager.getReservedFor(vehicle.vehicleManagerId.get()).get, + Some(vehicle), triggerId = inquiry.triggerId ) logger.warn( diff --git a/src/main/scala/beam/agentsim/agents/ridehail/DefaultRideHailDepotParkingManager.scala b/src/main/scala/beam/agentsim/agents/ridehail/DefaultRideHailDepotParkingManager.scala index c2bde51ce2f..63d718c77a5 100644 --- a/src/main/scala/beam/agentsim/agents/ridehail/DefaultRideHailDepotParkingManager.scala +++ b/src/main/scala/beam/agentsim/agents/ridehail/DefaultRideHailDepotParkingManager.scala @@ -342,6 +342,8 @@ object DefaultRideHailDepotParkingManager { // for this reason, a higher max radius is reasonable. val SearchStartRadius: Double = 40000.0 // meters val SearchMaxRadius: Int = 80465 // 50 miles, in meters + val FractionOfSameTypeZones: Double = 0.2 // 20% + val MinNumberOfSameTypeZones: Int = 5 val outputRidehailParkingFileName = "ridehailParking.csv" def apply[GEO: GeoLevel]( @@ -369,6 +371,8 @@ object DefaultRideHailDepotParkingManager { beamServices.geo.distUTMInMeters, DefaultRideHailDepotParkingManager.SearchStartRadius, DefaultRideHailDepotParkingManager.SearchMaxRadius, + DefaultRideHailDepotParkingManager.FractionOfSameTypeZones, + DefaultRideHailDepotParkingManager.MinNumberOfSameTypeZones, boundingBox, beamServices.beamConfig.matsim.modules.global.randomSeed, beamServices.beamScenario.fuelTypePrices, diff --git a/src/main/scala/beam/agentsim/agents/ridehail/RideHailDepotParkingManager.scala b/src/main/scala/beam/agentsim/agents/ridehail/RideHailDepotParkingManager.scala index b83ceeb4d6d..350921e8589 100644 --- a/src/main/scala/beam/agentsim/agents/ridehail/RideHailDepotParkingManager.scala +++ b/src/main/scala/beam/agentsim/agents/ridehail/RideHailDepotParkingManager.scala @@ -19,7 +19,7 @@ abstract class RideHailDepotParkingManager[GEO: GeoLevel](parkingZones: Map[Id[P false } else { val parkingZone: ParkingZone[GEO] = parkingZones(release.stall.parkingZoneId) - val success = ParkingZone.releaseStall(parkingZone) + val success = searchFunctions.get.releaseStall(parkingZone) if (success) { totalStallsInUse -= 1 totalStallsAvailable += 1 diff --git a/src/main/scala/beam/agentsim/agents/vehicles/VehicleManager.scala b/src/main/scala/beam/agentsim/agents/vehicles/VehicleManager.scala index 667a94ef1f2..3b2b3dbf9c5 100644 --- a/src/main/scala/beam/agentsim/agents/vehicles/VehicleManager.scala +++ b/src/main/scala/beam/agentsim/agents/vehicles/VehicleManager.scala @@ -33,11 +33,11 @@ object VehicleManager extends LazyLogging { case class ReservedFor(managerId: Id[VehicleManager], managerType: TypeEnum.VehicleManagerType) { - override def hashCode: Int = toString.hashCode + override val hashCode: Int = toString.hashCode override def toString: String = { managerType match { - case TypeEnum.NoManager => NoManager.toString + case TypeEnum.NoManager => managerType.toString case _ => managerType + s"($managerId)" } } diff --git a/src/main/scala/beam/agentsim/infrastructure/ChargingFunctions.scala b/src/main/scala/beam/agentsim/infrastructure/ChargingFunctions.scala index d219e1a36a9..7a7d1f58234 100644 --- a/src/main/scala/beam/agentsim/infrastructure/ChargingFunctions.scala +++ b/src/main/scala/beam/agentsim/infrastructure/ChargingFunctions.scala @@ -26,6 +26,8 @@ class ChargingFunctions[GEO: GeoLevel]( maxSearchRadius: Double, searchMaxDistanceRelativeToEllipseFoci: Double, enrouteDuration: Double, + fractionOfSameTypeZones: Double, + minNumberOfSameTypeZones: Int, boundingBox: Envelope, seed: Int, mnlParkingConfig: BeamConfig.Beam.Agentsim.Agents.Parking.MulitnomialLogit, @@ -41,6 +43,8 @@ class ChargingFunctions[GEO: GeoLevel]( maxSearchRadius, searchMaxDistanceRelativeToEllipseFoci, enrouteDuration, + fractionOfSameTypeZones, + minNumberOfSameTypeZones, boundingBox, seed, mnlParkingConfig diff --git a/src/main/scala/beam/agentsim/infrastructure/ChargingNetwork.scala b/src/main/scala/beam/agentsim/infrastructure/ChargingNetwork.scala index 52b876c3a04..d98f303f898 100644 --- a/src/main/scala/beam/agentsim/infrastructure/ChargingNetwork.scala +++ b/src/main/scala/beam/agentsim/infrastructure/ChargingNetwork.scala @@ -174,6 +174,8 @@ object ChargingNetwork extends LazyLogging { beamConfig.beam.agentsim.agents.parking.maxSearchRadius, beamConfig.beam.agentsim.agents.parking.searchMaxDistanceRelativeToEllipseFoci, beamConfig.beam.agentsim.agents.vehicles.enroute.estimateOfMeanChargingDurationInSecond, + beamConfig.beam.agentsim.agents.parking.fractionOfSameTypeZones, + beamConfig.beam.agentsim.agents.parking.minNumberOfSameTypeZones, envelopeInUTM, beamConfig.matsim.modules.global.randomSeed, beamConfig.beam.agentsim.agents.parking.mulitnomialLogit, diff --git a/src/main/scala/beam/agentsim/infrastructure/DefaultRidehailFunctions.scala b/src/main/scala/beam/agentsim/infrastructure/DefaultRidehailFunctions.scala index 91817fa70dc..cd16aeefc3f 100644 --- a/src/main/scala/beam/agentsim/infrastructure/DefaultRidehailFunctions.scala +++ b/src/main/scala/beam/agentsim/infrastructure/DefaultRidehailFunctions.scala @@ -29,6 +29,8 @@ class DefaultRidehailFunctions[GEO: GeoLevel]( distanceFunction: (Coord, Coord) => Double, minSearchRadius: Double, maxSearchRadius: Double, + fractionOfSameTypeZones: Double, + minNumberOfSameTypeZones: Int, boundingBox: Envelope, seed: Int, fuelTypePrices: Map[FuelType, Double], @@ -44,6 +46,8 @@ class DefaultRidehailFunctions[GEO: GeoLevel]( maxSearchRadius, 0.0, 0.0, + fractionOfSameTypeZones, + minNumberOfSameTypeZones, boundingBox, seed ) { diff --git a/src/main/scala/beam/agentsim/infrastructure/HierarchicalParkingManager.scala b/src/main/scala/beam/agentsim/infrastructure/HierarchicalParkingManager.scala index 4926515fe73..43101e411da 100644 --- a/src/main/scala/beam/agentsim/infrastructure/HierarchicalParkingManager.scala +++ b/src/main/scala/beam/agentsim/infrastructure/HierarchicalParkingManager.scala @@ -70,6 +70,8 @@ class HierarchicalParkingManager( maxSearchRadius, 0.0, 0.0, + 1.0, + 1, boundingBox, seed, mnlParkingConfig @@ -104,7 +106,7 @@ class HierarchicalParkingManager( tazSearchFunctions.searchForParkingStall(inquiry) val (parkingStall: ParkingStall, parkingZone: ParkingZone[Link]) = - tazLinks.get(tazParkingZone.geoId.asInstanceOf[Id[TAZ]]) match { + tazLinks.get(tazParkingZone.geoId) match { case Some(linkQuadTree) => val foundZoneDescription = ParkingZoneDescription.describeParkingZone(tazParkingZone) val startingPoint = @@ -162,7 +164,7 @@ class HierarchicalParkingManager( ) ParkingZone.claimStall(parkingZone) - ParkingZone.claimStall(tazParkingZone) + tazSearchFunctions.claimStall(tazParkingZone) } Some(ParkingInquiryResponse(parkingStall, inquiry.requestId, inquiry.triggerId)) @@ -186,7 +188,7 @@ class HierarchicalParkingManager( val tazZoneId = linkZoneToTazZoneMap(parkingZoneId) val tazZone = tazParkingZones(tazZoneId) ParkingZone.releaseStall(linkZone) - ParkingZone.releaseStall(tazZone) + tazSearchFunctions.releaseStall(tazZone) } } diff --git a/src/main/scala/beam/agentsim/infrastructure/InfrastructureFunctions.scala b/src/main/scala/beam/agentsim/infrastructure/InfrastructureFunctions.scala index 89893cd29de..83401371eb4 100644 --- a/src/main/scala/beam/agentsim/infrastructure/InfrastructureFunctions.scala +++ b/src/main/scala/beam/agentsim/infrastructure/InfrastructureFunctions.scala @@ -6,6 +6,7 @@ import beam.agentsim.infrastructure.charging.ChargingPointType import beam.agentsim.infrastructure.parking.ParkingZone.UbiqiutousParkingAvailability import beam.agentsim.infrastructure.parking.ParkingZoneSearch.{ ParkingAlternative, + ParkingZoneCollection, ParkingZoneSearchConfiguration, ParkingZoneSearchParams, ParkingZoneSearchResult @@ -29,12 +30,14 @@ abstract class InfrastructureFunctions[GEO: GeoLevel]( maxSearchRadius: Double, searchMaxDistanceRelativeToEllipseFoci: Double, enrouteDuration: Double, + fractionOfSameTypeZones: Double, + minNumberOfSameTypeZones: Int, boundingBox: Envelope, seed: Int ) extends StrictLogging { - protected val zoneSearchTree: ParkingZoneSearch.ZoneSearchTree[GEO] = - ParkingZoneFileUtils.createZoneSearchTree(parkingZones.values.toSeq) + protected val zoneCollections: Map[Id[GEO], ParkingZoneCollection[GEO]] = + ParkingZoneSearch.createZoneCollections(parkingZones.values.toSeq) protected val mnlMultiplierParameters: Map[ParkingMNL.Parameters, UtilityFunctionOperation] @@ -98,7 +101,9 @@ abstract class InfrastructureFunctions[GEO: GeoLevel]( searchMaxDistanceRelativeToEllipseFoci, boundingBox, distanceFunction, - enrouteDuration + enrouteDuration, + fractionOfSameTypeZones, + minNumberOfSameTypeZones ) def searchForParkingStall(inquiry: ParkingInquiry): Option[ParkingZoneSearch.ParkingZoneSearchResult[GEO]] = { @@ -122,11 +127,12 @@ abstract class InfrastructureFunctions[GEO: GeoLevel]( inquiry.parkingDuration, inquiry.searchMode, mnlMultiplierParameters, - zoneSearchTree, + zoneCollections, parkingZones, geoQuadTree, new Random(seed), - inquiry.departureLocation + inquiry.departureLocation, + inquiry.reservedFor ) val closestZone = @@ -219,6 +225,18 @@ abstract class InfrastructureFunctions[GEO: GeoLevel]( result } + def claimStall(parkingZone: ParkingZone[GEO]): Boolean = { + val result = ParkingZone.claimStall(parkingZone) + zoneCollections.get(parkingZone.geoId).foreach(_.claimZone(parkingZone)) + result + } + + def releaseStall(parkingZone: ParkingZone[GEO]): Boolean = { + val result = ParkingZone.releaseStall(parkingZone) + zoneCollections.get(parkingZone.geoId).foreach(_.releaseZone(parkingZone)) + result + } + } object InfrastructureFunctions { diff --git a/src/main/scala/beam/agentsim/infrastructure/ParallelParkingManager.scala b/src/main/scala/beam/agentsim/infrastructure/ParallelParkingManager.scala index 8424d2d3266..24429be06ee 100644 --- a/src/main/scala/beam/agentsim/infrastructure/ParallelParkingManager.scala +++ b/src/main/scala/beam/agentsim/infrastructure/ParallelParkingManager.scala @@ -38,6 +38,8 @@ class ParallelParkingManager( boundingBox: Envelope, minSearchRadius: Double, maxSearchRadius: Double, + fractionOfSameTypeZones: Double, + minNumberOfSameTypeZones: Int, seed: Int, mnlParkingConfig: BeamConfig.Beam.Agentsim.Agents.Parking.MulitnomialLogit ) extends ParkingNetwork[TAZ](parkingZones) { @@ -72,6 +74,8 @@ class ParallelParkingManager( boundingBox, minSearchRadius, maxSearchRadius, + fractionOfSameTypeZones, + minNumberOfSameTypeZones, seed, mnlParkingConfig ) @@ -181,6 +185,8 @@ object ParallelParkingManager extends LazyLogging { boundingBox, beamConfig.beam.agentsim.agents.parking.minSearchRadius, beamConfig.beam.agentsim.agents.parking.maxSearchRadius, + beamConfig.beam.agentsim.agents.parking.fractionOfSameTypeZones, + beamConfig.beam.agentsim.agents.parking.minNumberOfSameTypeZones, seed, beamConfig.beam.agentsim.agents.parking.mulitnomialLogit ) diff --git a/src/main/scala/beam/agentsim/infrastructure/ParkingFunctions.scala b/src/main/scala/beam/agentsim/infrastructure/ParkingFunctions.scala index 96603ea2957..7c25269f638 100644 --- a/src/main/scala/beam/agentsim/infrastructure/ParkingFunctions.scala +++ b/src/main/scala/beam/agentsim/infrastructure/ParkingFunctions.scala @@ -24,6 +24,8 @@ class ParkingFunctions[GEO: GeoLevel]( maxSearchRadius: Double, searchMaxDistanceRelativeToEllipseFoci: Double, enrouteDuration: Double, + fractionOfSameTypeZones: Double, + minNumberOfSameTypeZones: Int, boundingBox: Envelope, seed: Int, mnlParkingConfig: BeamConfig.Beam.Agentsim.Agents.Parking.MulitnomialLogit @@ -37,6 +39,8 @@ class ParkingFunctions[GEO: GeoLevel]( maxSearchRadius, searchMaxDistanceRelativeToEllipseFoci, enrouteDuration, + fractionOfSameTypeZones, + minNumberOfSameTypeZones, boundingBox, seed ) { @@ -218,8 +222,6 @@ class ParkingFunctions[GEO: GeoLevel]( inquiry: ParkingInquiry, preferredParkingTypes: Set[ParkingType] ): Boolean = { - val hasAvailability: Boolean = parkingZones(zone.parkingZoneId).stallsAvailable > 0 - val validParkingType: Boolean = preferredParkingTypes.contains(zone.parkingType) val isValidTime = inquiry.beamVehicle.forall(vehicle => @@ -228,11 +230,7 @@ class ParkingFunctions[GEO: GeoLevel]( .forall(_.contains(inquiry.destinationUtm.time % (24 * 3600))) ) - val isValidVehicleManager = inquiry.beamVehicle.forall { vehicle => - zone.reservedFor.managerType == VehicleManager.TypeEnum.Default || zone.reservedFor.managerId == inquiry.reservedFor.managerId - } - - hasAvailability & validParkingType & isValidTime & isValidVehicleManager + validParkingType && isValidTime } /** diff --git a/src/main/scala/beam/agentsim/infrastructure/ParkingManagerBenchmark.scala b/src/main/scala/beam/agentsim/infrastructure/ParkingManagerBenchmark.scala index f63247977d7..bee26e44169 100644 --- a/src/main/scala/beam/agentsim/infrastructure/ParkingManagerBenchmark.scala +++ b/src/main/scala/beam/agentsim/infrastructure/ParkingManagerBenchmark.scala @@ -59,25 +59,26 @@ class ParkingManagerBenchmark( object ParkingManagerBenchmark extends StrictLogging { -// val pathToPlans: String = "D:/Work/beam/ParallelJDEQSim/sfbay-smart-base/0.plans.xml.gz" - val pathToPlans: String = "https://beam-outputs.s3.us-east-2.amazonaws.com/parallel_parking_manager/0.plans.xml.gz" + val pathToPlans: String = "data_files/sfbay-smartbaseline/0.plans.xml.gz" + // val pathToPlans: String = "https://beam-outputs.s3.us-east-2.amazonaws.com/parallel_parking_manager/0.plans.xml.gz" -// val pathToTazParking: String = "D:/Work/beam/ParallelJDEQSim/sfbay-smart-base/parking/taz-parking-unlimited-fast-limited-l2-150-baseline.csv" - val pathToTazParking: String = - "https://beam-outputs.s3.us-east-2.amazonaws.com/parallel_parking_manager/taz-parking-unlimited-fast-limited-l2-150-baseline.csv.gz" +// val pathToTazParking: String = "production/sfbay/gemini/infrastructure/4a_output_2022_Apr_13_pubClust_withFees_aggregated.csv" + val pathToTazParking: String = "production/sfbay/gemini/infrastructure/init1-7_2022_Feb_03_wgs84_withFees_cleaned.csv" + // val pathToTazParking: String = + // "https://beam-outputs.s3.us-east-2.amazonaws.com/parallel_parking_manager/taz-parking-unlimited-fast-limited-l2-150-baseline.csv.gz" -// val pathToLinkParking: String = "D:/Work/beam/ParallelJDEQSim/sfbay-smart-base/parking/link-parking-unlimited-fast-limited-l2-150-baseline.csv" - val pathToLinkParking: String = - "https://beam-outputs.s3.us-east-2.amazonaws.com/parallel_parking_manager/link-parking-unlimited-fast-limited-l2-150-baseline.csv.gz" + val pathToLinkParking: String = "production/sfbay/gemini/infrastructure/init1-7_2022_Feb_03_wgs84_withFees_link.csv" + // val pathToLinkParking: String = + // "https://beam-outputs.s3.us-east-2.amazonaws.com/parallel_parking_manager/link-parking-unlimited-fast-limited-l2-150-baseline.csv.gz" -// val pathToTAZ: String = "D:/Work/beam/ParallelJDEQSim/sfbay-smart-base/taz-centers.csv" - val pathToTAZ: String = "https://beam-outputs.s3.us-east-2.amazonaws.com/parallel_parking_manager/taz-centers.csv.gz" + val pathToTAZ: String = "production/sfbay/taz-centers.csv" + // val pathToTAZ: String = "https://beam-outputs.s3.us-east-2.amazonaws.com/parallel_parking_manager/taz-centers.csv.gz" -// val pathToNetwork: String = "D:/Work/beam/ParallelJDEQSim/sfbay-smart-base/outputNetwork.xml.gz" - val pathToNetwork: String = - "https://beam-outputs.s3.us-east-2.amazonaws.com/parallel_parking_manager/outputNetwork.xml.gz" + val pathToNetwork: String = "production/sfbay/r5-simple-no-local/physsim-network.xml" + // val pathToNetwork: String = + // "https://beam-outputs.s3.us-east-2.amazonaws.com/parallel_parking_manager/outputNetwork.xml.gz" - val parkingStallCountScalingFactor: Double = 0.13 + val parkingStallCountScalingFactor: Double = 1.0 val parkingCostScalingFactor: Double = 1.0 val typeSafeConfig: Config = ConfigFactory @@ -109,7 +110,7 @@ object ParkingManagerBenchmark extends StrictLogging { val seed: Int = 42 val nTimes: Int = 1 - val fractionToBench: Double = 0.3 + val fractionToBench: Double = 0.1 def main(args: Array[String]): Unit = { implicit val ec: ExecutionContext = scala.concurrent.ExecutionContext.Implicits.global diff --git a/src/main/scala/beam/agentsim/infrastructure/ZonalParkingManager.scala b/src/main/scala/beam/agentsim/infrastructure/ZonalParkingManager.scala index 64d5a32b7ed..a540be12174 100755 --- a/src/main/scala/beam/agentsim/infrastructure/ZonalParkingManager.scala +++ b/src/main/scala/beam/agentsim/infrastructure/ZonalParkingManager.scala @@ -45,6 +45,8 @@ object ZonalParkingManager extends LazyLogging { boundingBox: Envelope, minSearchRadius: Double, maxSearchRadius: Double, + fractionOfSameTypeZones: Double, + minNumberOfSameTypeZones: Int, seed: Int, mnlParkingConfig: BeamConfig.Beam.Agentsim.Agents.Parking.MulitnomialLogit ): ZonalParkingManager[GEO] = { @@ -65,6 +67,8 @@ object ZonalParkingManager extends LazyLogging { maxSearchRadius, 0.0, 0.0, + fractionOfSameTypeZones, + minNumberOfSameTypeZones, boundingBox, seed, mnlParkingConfig @@ -96,6 +100,8 @@ object ZonalParkingManager extends LazyLogging { envelopeInUTM, beamConfig.beam.agentsim.agents.parking.minSearchRadius, beamConfig.beam.agentsim.agents.parking.maxSearchRadius, + beamConfig.beam.agentsim.agents.parking.fractionOfSameTypeZones, + beamConfig.beam.agentsim.agents.parking.minNumberOfSameTypeZones, beamConfig.matsim.modules.global.randomSeed, beamConfig.beam.agentsim.agents.parking.mulitnomialLogit ) @@ -138,6 +144,8 @@ object ZonalParkingManager extends LazyLogging { boundingBox, minSearchRadius, maxSearchRadius, + 0.5, + 10, seed, mnlParkingConfig ) diff --git a/src/main/scala/beam/agentsim/infrastructure/parking/ParkingNetwork.scala b/src/main/scala/beam/agentsim/infrastructure/parking/ParkingNetwork.scala index 499c82ce3c6..2c2531b9a47 100644 --- a/src/main/scala/beam/agentsim/infrastructure/parking/ParkingNetwork.scala +++ b/src/main/scala/beam/agentsim/infrastructure/parking/ParkingNetwork.scala @@ -35,7 +35,7 @@ abstract class ParkingNetwork[GEO: GeoLevel](parkingZones: Map[Id[ParkingZoneId] else "non-charging"} stall for agent ${inquiry.requestId} in parkingZone ${parkingZone.parkingZoneId}" ) // update the parking stall data - val claimed: Boolean = ParkingZone.claimStall(parkingZone) + val claimed: Boolean = searchFunctions.get.claimStall(parkingZone) if (claimed) { totalStallsInUse += 1 totalStallsAvailable -= 1 @@ -61,7 +61,7 @@ abstract class ParkingNetwork[GEO: GeoLevel](parkingZones: Map[Id[ParkingZoneId] logger.debug("Attempting to release stall in zone {} which is an illegal parking zone id", parkingZoneId) false } else { - val releasedTemp: Boolean = ParkingZone.releaseStall(parkingZones(parkingZoneId)) + val releasedTemp: Boolean = searchFunctions.get.releaseStall(parkingZones(parkingZoneId)) if (releasedTemp) { totalStallsInUse -= 1 totalStallsAvailable += 1 diff --git a/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZone.scala b/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZone.scala index df32043d130..054d834c2ca 100644 --- a/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZone.scala +++ b/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZone.scala @@ -210,14 +210,11 @@ object ParkingZone extends LazyLogging { parkingZones: Map[Id[ParkingZoneId], ParkingZone[GEO]], parkingZoneId: Id[ParkingZoneId] ): Option[ParkingZone[GEO]] = { - if (!parkingZones.contains(parkingZoneId)) { + val result = parkingZones.get(parkingZoneId) + if (result.isEmpty) { logger.warn(s"attempting to access parking zone with illegal parkingZoneId $parkingZoneId, will be ignored") - None - } else { - Some { - parkingZones(parkingZoneId) - } } + result } /** diff --git a/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZoneSearch.scala b/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZoneSearch.scala index d8738f5f720..acd6a85f2a2 100644 --- a/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZoneSearch.scala +++ b/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZoneSearch.scala @@ -1,17 +1,21 @@ package beam.agentsim.infrastructure.parking import beam.agentsim.agents.choice.logit.MultinomialLogit +import beam.agentsim.agents.vehicles.VehicleCategory.VehicleCategory +import beam.agentsim.agents.vehicles.VehicleManager.{ReservedFor, TypeEnum} import beam.agentsim.infrastructure.ParkingInquiry.ParkingSearchMode import beam.agentsim.infrastructure.ParkingStall import beam.agentsim.infrastructure.charging._ import beam.agentsim.infrastructure.taz.TAZ import beam.router.BeamRouter.Location +import beam.utils.MathUtils import com.vividsolutions.jts.geom.Envelope import org.matsim.api.core.v01.{Coord, Id} import org.matsim.core.utils.collections.QuadTree import scala.annotation.tailrec import scala.collection.JavaConverters._ +import scala.collection.mutable import scala.util.Random object ParkingZoneSearch { @@ -48,6 +52,8 @@ object ParkingZoneSearch { boundingBox: Envelope, distanceFunction: (Coord, Coord) => Double, enrouteDuration: Double, + fractionOfSameTypeZones: Double, + minNumberOfSameTypeZones: Int, searchExpansionFactor: Double = 2.0 ) @@ -57,23 +63,22 @@ object ParkingZoneSearch { * @param destinationUTM destination of inquiry * @param parkingDuration duration of the activity agent wants to park for * @param parkingMNLConfig utility function which evaluates [[ParkingAlternative]]s - * @param zoneSearchTree a nested map lookup of [[ParkingZone]]s + * @param zoneCollections a nested map lookup of [[ParkingZone]]s * @param parkingZones the stored state of all [[ParkingZone]]s * @param zoneQuadTree [[ParkingZone]]s are associated with a TAZ, which are themselves stored in this Quad Tree * @param random random number generator - * @param parkingTypes the list of acceptable parking types allowed for this search */ case class ParkingZoneSearchParams[GEO]( destinationUTM: Location, parkingDuration: Double, searchMode: ParkingSearchMode, parkingMNLConfig: ParkingMNL.ParkingMNLConfig, - zoneSearchTree: ZoneSearchTree[GEO], + zoneCollections: Map[Id[GEO], ParkingZoneCollection[GEO]], parkingZones: Map[Id[ParkingZoneId], ParkingZone[GEO]], zoneQuadTree: QuadTree[GEO], random: Random, originUTM: Option[Location], - parkingTypes: Seq[ParkingType] = ParkingType.AllTypes + reservedFor: ReservedFor ) /** @@ -154,12 +159,14 @@ object ParkingZoneSearch { // ParkingZones as as ParkingAlternatives val alternatives: List[ParkingSearchAlternative[GEO]] = { for { - zone <- theseZones - parkingTypesSubtree <- params.zoneSearchTree.get(zone.getId).toList - parkingType <- params.parkingTypes - parkingZoneIds <- parkingTypesSubtree.get(parkingType).toList - parkingZoneId <- parkingZoneIds - parkingZone <- ParkingZone.getParkingZone(params.parkingZones, parkingZoneId) + zone <- theseZones + zoneCollection <- params.zoneCollections.get(zone.getId).toSeq + parkingZone <- zoneCollection.getFreeZones( + config.fractionOfSameTypeZones, + config.minNumberOfSameTypeZones, + params.reservedFor, + params.random + ) if parkingZoneFilterFunction(parkingZone) } yield { // wrap ParkingZone in a ParkingAlternative @@ -244,6 +251,88 @@ object ParkingZoneSearch { _search(SearchMode.getInstance(config, params)) } + /** + * This class "describes" a parking zone (i.e. extended type of parking zone). This allows to search for similar + * parking zones on other links or TAZes + * @param parkingType the parking type (Residential, Workplace, Public) + * @param chargingPointType the charging point type + * @param pricingModel the pricing model + * @param timeRestrictions the time restrictions + */ + case class ParkingZoneInfo( + parkingType: ParkingType, + chargingPointType: Option[ChargingPointType], + pricingModel: Option[PricingModel], + timeRestrictions: Map[VehicleCategory, Range] + ) + + object ParkingZoneInfo { + + def describeParkingZone(zone: ParkingZone[_]): ParkingZoneInfo = { + new ParkingZoneInfo( + zone.parkingType, + zone.chargingPointType, + zone.pricingModel, + zone.timeRestrictions + ) + } + } + + class ParkingZoneCollection[GEO](parkingZones: Seq[ParkingZone[GEO]]) { + + private val publicFreeZones: Map[ParkingZoneInfo, mutable.Set[ParkingZone[GEO]]] = + parkingZones.view + .filter(_.reservedFor.managerType == TypeEnum.Default) + .groupBy(ParkingZoneInfo.describeParkingZone) + .mapValues(zones => mutable.Set(zones: _*)) + .view + .force + + private val reservedFreeZones: Map[ReservedFor, mutable.Set[ParkingZone[GEO]]] = + parkingZones.view + .filter(_.reservedFor.managerType != TypeEnum.Default) + .groupBy(_.reservedFor) + .mapValues(zones => mutable.Set(zones: _*)) + .view + .force + + def getFreeZones( + fraction: Double, + min: Int, + reservedFor: ReservedFor, + rnd: Random + ): IndexedSeq[ParkingZone[GEO]] = { + ( + publicFreeZones.view.flatMap { case (_, zones) => + val numToTake = Math.max(MathUtils.doubleToInt(zones.size * fraction), min) + MathUtils.selectRandomElements(zones, numToTake, rnd) + } ++ + reservedFreeZones.getOrElse(reservedFor, Nil) + ).toIndexedSeq + } + + def claimZone(parkingZone: ParkingZone[GEO]): Unit = + if (parkingZone.stallsAvailable <= 0) { + for (set <- getCorrespondingZoneSet(parkingZone)) set -= parkingZone + } + + def releaseZone(parkingZone: ParkingZone[GEO]): Unit = + if (parkingZone.stallsAvailable > 0) { + for (set <- getCorrespondingZoneSet(parkingZone)) set += parkingZone + } + + private def getCorrespondingZoneSet(parkingZone: ParkingZone[GEO]): Option[mutable.Set[ParkingZone[GEO]]] = + if (parkingZone.reservedFor.managerType == TypeEnum.Default) { + publicFreeZones.get(ParkingZoneInfo.describeParkingZone(parkingZone)) + } else { + reservedFreeZones.get(parkingZone.reservedFor) + } + } + + def createZoneCollections[GEO](zones: Seq[ParkingZone[GEO]]): Map[Id[GEO], ParkingZoneCollection[GEO]] = { + zones.groupBy(_.geoId).mapValues(new ParkingZoneCollection(_)).view.force + } + trait SearchMode[GEO] { def lookupParkingZonesInNextSearchAreaUnlessThresholdReached(zoneQuadTree: QuadTree[GEO]): Option[List[GEO]] } diff --git a/src/main/scala/beam/sim/config/BeamConfig.scala b/src/main/scala/beam/sim/config/BeamConfig.scala index 8aa7a57c6e1..204ccd5bea4 100644 --- a/src/main/scala/beam/sim/config/BeamConfig.scala +++ b/src/main/scala/beam/sim/config/BeamConfig.scala @@ -53,13 +53,13 @@ object BeamConfig { scheduleMonitorTask: BeamConfig.Beam.Agentsim.ScheduleMonitorTask, schedulerParallelismWindow: scala.Int, simulationName: java.lang.String, + snapLocationAndRemoveInvalidInputs: scala.Boolean, taz: BeamConfig.Beam.Agentsim.Taz, thresholdForMakingParkingChoiceInMeters: scala.Int, thresholdForWalkingInMeters: scala.Int, timeBinSize: scala.Int, toll: BeamConfig.Beam.Agentsim.Toll, - tuning: BeamConfig.Beam.Agentsim.Tuning, - snapLocationAndRemoveInvalidInputs: scala.Boolean + tuning: BeamConfig.Beam.Agentsim.Tuning ) object Agentsim { @@ -717,7 +717,9 @@ object BeamConfig { } case class Parking( + fractionOfSameTypeZones: scala.Double, maxSearchRadius: scala.Double, + minNumberOfSameTypeZones: scala.Int, minSearchRadius: scala.Double, mulitnomialLogit: BeamConfig.Beam.Agentsim.Agents.Parking.MulitnomialLogit, rangeAnxietyBuffer: scala.Double, @@ -774,7 +776,11 @@ object BeamConfig { def apply(c: com.typesafe.config.Config): BeamConfig.Beam.Agentsim.Agents.Parking = { BeamConfig.Beam.Agentsim.Agents.Parking( + fractionOfSameTypeZones = + if (c.hasPathOrNull("fractionOfSameTypeZones")) c.getDouble("fractionOfSameTypeZones") else 0.5, maxSearchRadius = if (c.hasPathOrNull("maxSearchRadius")) c.getDouble("maxSearchRadius") else 8046.72, + minNumberOfSameTypeZones = + if (c.hasPathOrNull("minNumberOfSameTypeZones")) c.getInt("minNumberOfSameTypeZones") else 10, minSearchRadius = if (c.hasPathOrNull("minSearchRadius")) c.getDouble("minSearchRadius") else 250.00, mulitnomialLogit = BeamConfig.Beam.Agentsim.Agents.Parking.MulitnomialLogit( if (c.hasPathOrNull("mulitnomialLogit")) c.getConfig("mulitnomialLogit") @@ -2202,6 +2208,8 @@ object BeamConfig { schedulerParallelismWindow = if (c.hasPathOrNull("schedulerParallelismWindow")) c.getInt("schedulerParallelismWindow") else 30, simulationName = if (c.hasPathOrNull("simulationName")) c.getString("simulationName") else "beamville", + snapLocationAndRemoveInvalidInputs = + c.hasPathOrNull("snapLocationAndRemoveInvalidInputs") && c.getBoolean("snapLocationAndRemoveInvalidInputs"), taz = BeamConfig.Beam.Agentsim.Taz( if (c.hasPathOrNull("taz")) c.getConfig("taz") else com.typesafe.config.ConfigFactory.parseString("taz{}") ), @@ -2219,11 +2227,7 @@ object BeamConfig { tuning = BeamConfig.Beam.Agentsim.Tuning( if (c.hasPathOrNull("tuning")) c.getConfig("tuning") else com.typesafe.config.ConfigFactory.parseString("tuning{}") - ), - snapLocationAndRemoveInvalidInputs = - if (c.hasPathOrNull("snapLocationAndRemoveInvalidInputs")) - c.getBoolean("snapLocationAndRemoveInvalidInputs") - else false + ) ) } } diff --git a/src/main/scala/beam/utils/MathUtils.scala b/src/main/scala/beam/utils/MathUtils.scala index 162365feb9f..676cfbd03cd 100755 --- a/src/main/scala/beam/utils/MathUtils.scala +++ b/src/main/scala/beam/utils/MathUtils.scala @@ -162,6 +162,40 @@ object MathUtils { def nanToZero(x: Double) = if (x.isNaN) { 0.0 } else { x } + /** + * It selects random elements out of a collection. + * It is designed to be performant on not indexed collections (like Sets). + * @param xs the collection + * @param n number of elements to select + * @param random a Random + * @tparam T type of elements + * @return an array of selected elements + */ + def selectRandomElements[T: ClassTag](xs: Iterable[T], n: Int, random: Random): Array[T] = { + val size = xs.size + val numToTake = Math.min(n, size) + val result = Array.ofDim[T](numToTake) + val it = xs.iterator + var originalElementsLeft = size + var i = 0 + while (i < numToTake) { + val elem = it.next() + val resultElementsLeft = numToTake - i + if (resultElementsLeft < originalElementsLeft) { + val probability = resultElementsLeft.toDouble / originalElementsLeft + if (random.nextDouble() < probability) { + result(i) = elem + i += 1 + } + } else { + result(i) = elem + i += 1 + } + originalElementsLeft -= 1 + } + result + } + def selectElementsByProbability[T]( rndSeed: Long, elementToProbability: T => Double, diff --git a/src/test/scala/beam/agentsim/infrastructure/ParallelParkingManagerSpec.scala b/src/test/scala/beam/agentsim/infrastructure/ParallelParkingManagerSpec.scala index 5853eefd418..c41fca566aa 100644 --- a/src/test/scala/beam/agentsim/infrastructure/ParallelParkingManagerSpec.scala +++ b/src/test/scala/beam/agentsim/infrastructure/ParallelParkingManagerSpec.scala @@ -362,9 +362,9 @@ class ParallelParkingManagerSpec zpm, new Coord(170308.0, 2964.0), "4", - ParkingZone.createId("cs_default(Any)_4_Residential_NA_FlatFee_0_2147483647"), + ParkingZone.createId("cs_default(Any)_4_Public_NA_FlatFee_0_2147483647"), FlatFee(0.0), - ParkingType.Residential, + ParkingType.Public, VehicleManager.AnyManager ) @@ -372,9 +372,9 @@ class ParallelParkingManagerSpec zpm, new Coord(166321.0, 1568.0), "1", - ParkingZone.createId("cs_default(Any)_1_Residential_NA_FlatFee_0_2147483647"), + ParkingZone.createId("cs_default(Any)_1_Public_NA_FlatFee_0_2147483647"), FlatFee(0.0), - ParkingType.Residential, + ParkingType.Public, VehicleManager.AnyManager ) @@ -382,9 +382,9 @@ class ParallelParkingManagerSpec zpm, new Coord(167141.3, 3326.017), "2", - ParkingZone.createId("cs_default(Any)_2_Residential_NA_FlatFee_0_2147483647"), + ParkingZone.createId("cs_default(Any)_2_Public_NA_FlatFee_0_2147483647"), FlatFee(0.0), - ParkingType.Residential, + ParkingType.Public, VehicleManager.AnyManager ) } diff --git a/src/test/scala/beam/agentsim/infrastructure/ZonalParkingManagerSpec.scala b/src/test/scala/beam/agentsim/infrastructure/ZonalParkingManagerSpec.scala index ba0a59e18cd..c543e4a96f6 100644 --- a/src/test/scala/beam/agentsim/infrastructure/ZonalParkingManagerSpec.scala +++ b/src/test/scala/beam/agentsim/infrastructure/ZonalParkingManagerSpec.scala @@ -9,7 +9,7 @@ import beam.agentsim.agents.vehicles.EnergyEconomyAttributes.Powertrain import beam.agentsim.agents.vehicles.VehicleManager.ReservedFor import beam.agentsim.agents.vehicles.{BeamVehicle, BeamVehicleType, VehicleManager} import beam.agentsim.events.SpaceTime -import beam.agentsim.infrastructure.parking.PricingModel.FlatFee +import beam.agentsim.infrastructure.parking.PricingModel.{Block, FlatFee} import beam.agentsim.infrastructure.parking._ import beam.agentsim.infrastructure.taz.{TAZ, TAZTreeMap} import beam.sim.common.{GeoUtils, GeoUtilsImpl} @@ -336,9 +336,9 @@ class ZonalParkingManagerSpec zpm, SpaceTime(new Coord(170308.0, 2964.0), 0), "4", - ParkingZone.createId("cs_default(Any)_4_Residential_NA_FlatFee_0_2147483647"), + ParkingZone.createId("cs_default(Any)_4_Public_NA_FlatFee_0_2147483647"), FlatFee(0.0), - ParkingType.Residential, + ParkingType.Public, "beamVilleCar" ) @@ -346,9 +346,9 @@ class ZonalParkingManagerSpec zpm, SpaceTime(new Coord(166321.0, 1568.0), 0), "1", - ParkingZone.createId("cs_default(Any)_1_Residential_NA_FlatFee_0_2147483647"), + ParkingZone.createId("cs_default(Any)_1_Public_NA_FlatFee_0_2147483647"), FlatFee(0.0), - ParkingType.Residential, + ParkingType.Public, "beamVilleCar" ) @@ -356,9 +356,9 @@ class ZonalParkingManagerSpec zpm, SpaceTime(new Coord(167141.3, 3326.017), 0), "2", - ParkingZone.createId("cs_default(Any)_2_Residential_NA_FlatFee_0_2147483647"), + ParkingZone.createId("cs_default(Any)_2_Public_NA_FlatFee_0_2147483647"), FlatFee(0.0), - ParkingType.Residential, + ParkingType.Public, "beamVilleCar" ) @@ -440,6 +440,8 @@ class ZonalParkingManagerSpec boundingBox, beamConfig.beam.agentsim.agents.parking.minSearchRadius, beamConfig.beam.agentsim.agents.parking.maxSearchRadius, + beamConfig.beam.agentsim.agents.parking.fractionOfSameTypeZones, + beamConfig.beam.agentsim.agents.parking.minNumberOfSameTypeZones, randomSeed, beamConfig.beam.agentsim.agents.parking.mulitnomialLogit ) @@ -448,8 +450,8 @@ class ZonalParkingManagerSpec zonesMap, SpaceTime(new Coord(170308.0, 2964.0), 0), "4", - ParkingZone.createId("cs_default(Any)_4_Residential_NA_FlatFee_199_1144"), - FlatFee(1.99), + ParkingZone.createId("cs_default(Any)_4_Residential_NA_Block_199_1144"), + Block(1.99, 3600), ParkingType.Residential, "beamVilleCar" ) diff --git a/src/test/scala/beam/utils/MathUtilsSpec.scala b/src/test/scala/beam/utils/MathUtilsSpec.scala index 1e647a11109..c4a96b5dba2 100644 --- a/src/test/scala/beam/utils/MathUtilsSpec.scala +++ b/src/test/scala/beam/utils/MathUtilsSpec.scala @@ -65,4 +65,53 @@ class MathUtilsSpec extends AnyWordSpecLike with Matchers { } } } + + "selectRandomElements" when { + "provided with a collection and n is close to the collection size" should { + "return n elements" in { + val originalElements = 1 to 100 + val seed = Random.nextInt() + val result = MathUtils.selectRandomElements(originalElements, 90, new Random(seed)).toIndexedSeq + withClue(s"seed = $seed; ") { + result should have size 90 + originalElements should contain allElementsOf result + result.distinct should contain theSameElementsAs result + } + } + } + "provided with a collection an n is small" should { + "return n elements" in { + val originalElements = 1 to 100 + val seed = Random.nextInt() + val result = MathUtils.selectRandomElements(originalElements, 9, new Random(seed)).toIndexedSeq + withClue(s"seed = $seed; ") { + result should have size 9 + originalElements should contain allElementsOf result + result.distinct should contain theSameElementsAs result + } + } + } + "provided with a collection and n = collection.size" should { + "return all the collection elements" in { + val originalElements = 1 to 100 + val result = MathUtils.selectRandomElements(originalElements, 100, new Random()).toIndexedSeq + result should have size 100 + result should contain allElementsOf originalElements + } + } + "provided with a collection and n > collection.size" should { + "return all the collection elements" in { + val originalElements = 1 to 100 + val result = MathUtils.selectRandomElements(originalElements, 500, new Random()).toIndexedSeq + result should have size 100 + result should contain allElementsOf originalElements + } + } + "provided with an empty collection" should { + "return all an empty collection" in { + MathUtils.selectRandomElements(Nil, 0, new Random()) shouldBe empty + MathUtils.selectRandomElements(Nil, 100, new Random()) shouldBe empty + } + } + } } diff --git a/test/input/sf-light/taz-parking.csv b/test/input/sf-light/taz-parking.csv index a5dfbaa4832..e8e022501d9 100644 --- a/test/input/sf-light/taz-parking.csv +++ b/test/input/sf-light/taz-parking.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ec529a2d978a87a4117a19b4f8cada0f9c521faa21c3578a17d91aa4298a1b28 -size 1636492 +oid sha256:093a26c285c5bd9ca090c185697778e3f4ac663eae6ca33e5188f21157372e24 +size 1636497 From cd13262de417b793cf34d0396c164fd1858fc7f7 Mon Sep 17 00:00:00 2001 From: Grigory D Date: Sat, 23 Apr 2022 13:13:50 +0200 Subject: [PATCH 10/25] random seed in beam-template.conf --- src/main/resources/beam-template.conf | 1 + src/main/scala/beam/sim/BeamHelper.scala | 5 +++- .../scala/beam/sim/config/BeamConfig.scala | 23 ++++++++----------- .../sim/population/PopulationScaling.scala | 5 ++-- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/main/resources/beam-template.conf b/src/main/resources/beam-template.conf index 1b5b890d40d..8b669da4c42 100755 --- a/src/main/resources/beam-template.conf +++ b/src/main/resources/beam-template.conf @@ -20,6 +20,7 @@ beam.input.lastBaseOutputDir = ${beam.outputs.baseOutputDirectory} beam.input.simulationPrefix = ${beam.agentsim.simulationName} beam.agentsim.simulationName = "beamville" +beam.agentsim.randomSeedForPopulationSampling = "int?" beam.agentsim.agentSampleSizeAsFractionOfPopulation = "double | 1.0" beam.agentsim.fractionOfPlansWithSingleActivity = "double | 0.0" beam.agentsim.thresholdForWalkingInMeters = 100 diff --git a/src/main/scala/beam/sim/BeamHelper.scala b/src/main/scala/beam/sim/BeamHelper.scala index f28e45b1cf4..aec6efc35bd 100755 --- a/src/main/scala/beam/sim/BeamHelper.scala +++ b/src/main/scala/beam/sim/BeamHelper.scala @@ -985,7 +985,10 @@ trait BeamHelper extends LazyLogging { Kamon.init(config.withFallback(ConfigFactory.load())) } - logger.info("Agentsim random seed for population scaling is set to {}.", beamConfig.beam.agentsim.randomSeed) + logger.info( + "Agentsim random seed for population scaling is set to {}.", + beamConfig.beam.agentsim.randomSeedForPopulationSampling + ) logger.info("Starting beam on branch {} at commit {}.", BashUtils.getBranch, BashUtils.getCommitHash) logger.info( diff --git a/src/main/scala/beam/sim/config/BeamConfig.scala b/src/main/scala/beam/sim/config/BeamConfig.scala index 8aa7a57c6e1..2beab8edcdb 100644 --- a/src/main/scala/beam/sim/config/BeamConfig.scala +++ b/src/main/scala/beam/sim/config/BeamConfig.scala @@ -2,8 +2,6 @@ package beam.sim.config -import scala.util.Random - case class BeamConfig( beam: BeamConfig.Beam, matsim: BeamConfig.Matsim @@ -39,7 +37,6 @@ object BeamConfig { object Beam { case class Agentsim( - randomSeed: scala.Int, agentSampleSizeAsFractionOfPopulation: scala.Double, agents: BeamConfig.Beam.Agentsim.Agents, chargingNetworkManager: BeamConfig.Beam.Agentsim.ChargingNetworkManager, @@ -49,17 +46,18 @@ object BeamConfig { h3taz: BeamConfig.Beam.Agentsim.H3taz, lastIteration: scala.Int, populationAdjustment: java.lang.String, + randomSeedForPopulationSampling: scala.Option[scala.Int], scenarios: BeamConfig.Beam.Agentsim.Scenarios, scheduleMonitorTask: BeamConfig.Beam.Agentsim.ScheduleMonitorTask, schedulerParallelismWindow: scala.Int, simulationName: java.lang.String, + snapLocationAndRemoveInvalidInputs: scala.Boolean, taz: BeamConfig.Beam.Agentsim.Taz, thresholdForMakingParkingChoiceInMeters: scala.Int, thresholdForWalkingInMeters: scala.Int, timeBinSize: scala.Int, toll: BeamConfig.Beam.Agentsim.Toll, - tuning: BeamConfig.Beam.Agentsim.Tuning, - snapLocationAndRemoveInvalidInputs: scala.Boolean + tuning: BeamConfig.Beam.Agentsim.Tuning ) object Agentsim { @@ -2163,10 +2161,6 @@ object BeamConfig { def apply(c: com.typesafe.config.Config): BeamConfig.Beam.Agentsim = { BeamConfig.Beam.Agentsim( - randomSeed = - if (c.hasPathOrNull("randomSeed")) - c.getInt("randomSeed") - else new Random().nextInt(), agentSampleSizeAsFractionOfPopulation = if (c.hasPathOrNull("agentSampleSizeAsFractionOfPopulation")) c.getDouble("agentSampleSizeAsFractionOfPopulation") @@ -2191,6 +2185,9 @@ object BeamConfig { lastIteration = if (c.hasPathOrNull("lastIteration")) c.getInt("lastIteration") else 0, populationAdjustment = if (c.hasPathOrNull("populationAdjustment")) c.getString("populationAdjustment") else "DEFAULT_ADJUSTMENT", + randomSeedForPopulationSampling = + if (c.hasPathOrNull("randomSeedForPopulationSampling")) Some(c.getInt("randomSeedForPopulationSampling")) + else None, scenarios = BeamConfig.Beam.Agentsim.Scenarios( if (c.hasPathOrNull("scenarios")) c.getConfig("scenarios") else com.typesafe.config.ConfigFactory.parseString("scenarios{}") @@ -2202,6 +2199,8 @@ object BeamConfig { schedulerParallelismWindow = if (c.hasPathOrNull("schedulerParallelismWindow")) c.getInt("schedulerParallelismWindow") else 30, simulationName = if (c.hasPathOrNull("simulationName")) c.getString("simulationName") else "beamville", + snapLocationAndRemoveInvalidInputs = + c.hasPathOrNull("snapLocationAndRemoveInvalidInputs") && c.getBoolean("snapLocationAndRemoveInvalidInputs"), taz = BeamConfig.Beam.Agentsim.Taz( if (c.hasPathOrNull("taz")) c.getConfig("taz") else com.typesafe.config.ConfigFactory.parseString("taz{}") ), @@ -2219,11 +2218,7 @@ object BeamConfig { tuning = BeamConfig.Beam.Agentsim.Tuning( if (c.hasPathOrNull("tuning")) c.getConfig("tuning") else com.typesafe.config.ConfigFactory.parseString("tuning{}") - ), - snapLocationAndRemoveInvalidInputs = - if (c.hasPathOrNull("snapLocationAndRemoveInvalidInputs")) - c.getBoolean("snapLocationAndRemoveInvalidInputs") - else false + ) ) } } diff --git a/src/main/scala/beam/sim/population/PopulationScaling.scala b/src/main/scala/beam/sim/population/PopulationScaling.scala index a04f2fad126..e5a4a487cc6 100644 --- a/src/main/scala/beam/sim/population/PopulationScaling.scala +++ b/src/main/scala/beam/sim/population/PopulationScaling.scala @@ -1,7 +1,6 @@ package beam.sim.population import beam.sim.config.BeamConfig -import beam.sim.metrics.BeamStaticMetricsWriter import beam.sim.{BeamScenario, BeamServices, BeamWarmStart} import beam.utils.CloseableUtil.RichCloseable import beam.utils.MathUtils @@ -126,7 +125,9 @@ class PopulationScaling extends LazyLogging { val numAgents = math.round( beamConfig.beam.agentsim.agentSampleSizeAsFractionOfPopulation * scenario.getPopulation.getPersons.size() ) - val rand = new Random(beamServices.beamConfig.beam.agentsim.randomSeed) + val rand = new Random( + beamServices.beamConfig.beam.agentsim.maybeRandomSeedForPopulationSampling.getOrElse(System.currentTimeMillis()) + ) val notSelectedHouseholdIds = mutable.Set[Id[Household]]() val notSelectedVehicleIds = mutable.Set[Id[Vehicle]]() val notSelectedPersonIds = mutable.Set[Id[Person]]() From 90bd46625a47c6b9900b75222f5f6c6efa00f9df Mon Sep 17 00:00:00 2001 From: Grigory D Date: Sat, 23 Apr 2022 13:33:45 +0200 Subject: [PATCH 11/25] fix comp --- src/main/scala/beam/sim/BeamHelper.scala | 2 +- src/main/scala/beam/sim/config/BeamConfig.scala | 4 ++-- src/main/scala/beam/sim/population/PopulationScaling.scala | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/scala/beam/sim/BeamHelper.scala b/src/main/scala/beam/sim/BeamHelper.scala index aec6efc35bd..f478370f61b 100755 --- a/src/main/scala/beam/sim/BeamHelper.scala +++ b/src/main/scala/beam/sim/BeamHelper.scala @@ -987,7 +987,7 @@ trait BeamHelper extends LazyLogging { logger.info( "Agentsim random seed for population scaling is set to {}.", - beamConfig.beam.agentsim.randomSeedForPopulationSampling + beamConfig.beam.agentsim.maybeRandomSeedForPopulationSampling ) logger.info("Starting beam on branch {} at commit {}.", BashUtils.getBranch, BashUtils.getCommitHash) diff --git a/src/main/scala/beam/sim/config/BeamConfig.scala b/src/main/scala/beam/sim/config/BeamConfig.scala index 2beab8edcdb..257c3247102 100644 --- a/src/main/scala/beam/sim/config/BeamConfig.scala +++ b/src/main/scala/beam/sim/config/BeamConfig.scala @@ -46,7 +46,7 @@ object BeamConfig { h3taz: BeamConfig.Beam.Agentsim.H3taz, lastIteration: scala.Int, populationAdjustment: java.lang.String, - randomSeedForPopulationSampling: scala.Option[scala.Int], + maybeRandomSeedForPopulationSampling: scala.Option[scala.Long], scenarios: BeamConfig.Beam.Agentsim.Scenarios, scheduleMonitorTask: BeamConfig.Beam.Agentsim.ScheduleMonitorTask, schedulerParallelismWindow: scala.Int, @@ -2185,7 +2185,7 @@ object BeamConfig { lastIteration = if (c.hasPathOrNull("lastIteration")) c.getInt("lastIteration") else 0, populationAdjustment = if (c.hasPathOrNull("populationAdjustment")) c.getString("populationAdjustment") else "DEFAULT_ADJUSTMENT", - randomSeedForPopulationSampling = + maybeRandomSeedForPopulationSampling = if (c.hasPathOrNull("randomSeedForPopulationSampling")) Some(c.getInt("randomSeedForPopulationSampling")) else None, scenarios = BeamConfig.Beam.Agentsim.Scenarios( diff --git a/src/main/scala/beam/sim/population/PopulationScaling.scala b/src/main/scala/beam/sim/population/PopulationScaling.scala index e5a4a487cc6..ea60397f40d 100644 --- a/src/main/scala/beam/sim/population/PopulationScaling.scala +++ b/src/main/scala/beam/sim/population/PopulationScaling.scala @@ -126,8 +126,7 @@ class PopulationScaling extends LazyLogging { beamConfig.beam.agentsim.agentSampleSizeAsFractionOfPopulation * scenario.getPopulation.getPersons.size() ) val rand = new Random( - beamServices.beamConfig.beam.agentsim.maybeRandomSeedForPopulationSampling.getOrElse(System.currentTimeMillis()) - ) + beamServices.beamConfig.beam.agentsim.maybeRandomSeedForPopulationSampling.getOrElse(System.currentTimeMillis().toInt).asInstanceOf[Integer]) val notSelectedHouseholdIds = mutable.Set[Id[Household]]() val notSelectedVehicleIds = mutable.Set[Id[Vehicle]]() val notSelectedPersonIds = mutable.Set[Id[Person]]() From 7996a95203898758561033a1b021a7532a884bd0 Mon Sep 17 00:00:00 2001 From: Grigory D Date: Sat, 23 Apr 2022 14:28:42 +0200 Subject: [PATCH 12/25] fix test --- src/main/scala/beam/sim/config/BeamConfig.scala | 2 +- src/test/scala/beam/sim/population/PopulationSamplingSpec.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/beam/sim/config/BeamConfig.scala b/src/main/scala/beam/sim/config/BeamConfig.scala index 257c3247102..de62730f64b 100644 --- a/src/main/scala/beam/sim/config/BeamConfig.scala +++ b/src/main/scala/beam/sim/config/BeamConfig.scala @@ -46,7 +46,7 @@ object BeamConfig { h3taz: BeamConfig.Beam.Agentsim.H3taz, lastIteration: scala.Int, populationAdjustment: java.lang.String, - maybeRandomSeedForPopulationSampling: scala.Option[scala.Long], + maybeRandomSeedForPopulationSampling: scala.Option[scala.Int], scenarios: BeamConfig.Beam.Agentsim.Scenarios, scheduleMonitorTask: BeamConfig.Beam.Agentsim.ScheduleMonitorTask, schedulerParallelismWindow: scala.Int, diff --git a/src/test/scala/beam/sim/population/PopulationSamplingSpec.scala b/src/test/scala/beam/sim/population/PopulationSamplingSpec.scala index b040893a92d..f65b3c93625 100644 --- a/src/test/scala/beam/sim/population/PopulationSamplingSpec.scala +++ b/src/test/scala/beam/sim/population/PopulationSamplingSpec.scala @@ -41,7 +41,7 @@ class PopulationSamplingSpec extends AnyWordSpecLike with Matchers with BeamHelp "beam.agentsim.agentSampleSizeAsFractionOfPopulation", ConfigValueFactory.fromAnyRef(0.5) ) - .withValue("beam.agentsim.randomSeed", ConfigValueFactory.fromAnyRef(seed)) + .withValue("beam.agentsim.randomSeedForPopulationSampling", ConfigValueFactory.fromAnyRef(seed)) .resolve() ) } From 3d8319120b58e1e5741e288a63bbe7f7fb15dbf6 Mon Sep 17 00:00:00 2001 From: GrigoryD Date: Sat, 23 Apr 2022 15:29:43 +0200 Subject: [PATCH 13/25] fix test and logging --- src/main/scala/beam/sim/BeamHelper.scala | 4 ---- src/main/scala/beam/sim/population/PopulationScaling.scala | 7 +++++-- .../scala/beam/sim/population/PopulationSamplingSpec.scala | 6 +++--- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/scala/beam/sim/BeamHelper.scala b/src/main/scala/beam/sim/BeamHelper.scala index f478370f61b..ffea122dc0f 100755 --- a/src/main/scala/beam/sim/BeamHelper.scala +++ b/src/main/scala/beam/sim/BeamHelper.scala @@ -985,10 +985,6 @@ trait BeamHelper extends LazyLogging { Kamon.init(config.withFallback(ConfigFactory.load())) } - logger.info( - "Agentsim random seed for population scaling is set to {}.", - beamConfig.beam.agentsim.maybeRandomSeedForPopulationSampling - ) logger.info("Starting beam on branch {} at commit {}.", BashUtils.getBranch, BashUtils.getCommitHash) logger.info( diff --git a/src/main/scala/beam/sim/population/PopulationScaling.scala b/src/main/scala/beam/sim/population/PopulationScaling.scala index ea60397f40d..0e7f71187ce 100644 --- a/src/main/scala/beam/sim/population/PopulationScaling.scala +++ b/src/main/scala/beam/sim/population/PopulationScaling.scala @@ -125,8 +125,11 @@ class PopulationScaling extends LazyLogging { val numAgents = math.round( beamConfig.beam.agentsim.agentSampleSizeAsFractionOfPopulation * scenario.getPopulation.getPersons.size() ) - val rand = new Random( - beamServices.beamConfig.beam.agentsim.maybeRandomSeedForPopulationSampling.getOrElse(System.currentTimeMillis().toInt).asInstanceOf[Integer]) + val rand = new Random(beamServices.beamConfig.beam.agentsim.maybeRandomSeedForPopulationSampling.getOrElse { + val seed = System.currentTimeMillis().toInt + logger.info("Agentsim maybeRandomSeedForPopulationSampling is set to {}.", seed) + seed + }) val notSelectedHouseholdIds = mutable.Set[Id[Household]]() val notSelectedVehicleIds = mutable.Set[Id[Vehicle]]() val notSelectedPersonIds = mutable.Set[Id[Person]]() diff --git a/src/test/scala/beam/sim/population/PopulationSamplingSpec.scala b/src/test/scala/beam/sim/population/PopulationSamplingSpec.scala index f65b3c93625..e8041ed8cc8 100644 --- a/src/test/scala/beam/sim/population/PopulationSamplingSpec.scala +++ b/src/test/scala/beam/sim/population/PopulationSamplingSpec.scala @@ -69,7 +69,7 @@ class PopulationSamplingSpec extends AnyWordSpecLike with Matchers with BeamHelp } "PopulationSampling" must { - "sample the same agents for the same randomSeed value" in { + "sample the same agents for the same randomSeedForPopulationSampling value" in { val samplingDataOne = getObjectsForPopulationSampling(1441) val samplingDataTwo = getObjectsForPopulationSampling(1441) val agentsBeforeSamplingOneSize = samplingDataOne._1.getPopulation.getPersons.keySet().size() @@ -98,7 +98,7 @@ class PopulationSamplingSpec extends AnyWordSpecLike with Matchers with BeamHelp agentsAfterSamplingOne shouldBe agentsAfterSamplingTwo } - "sample different agents if randomSeed is not set" in { + "sample different agents if randomSeedForPopulationSampling is not set" in { val samplingDataOne = getObjectsForPopulationSampling() val samplingDataTwo = getObjectsForPopulationSampling() val agentsBeforeSamplingOneSize = samplingDataOne._1.getPopulation.getPersons.keySet().size() @@ -126,7 +126,7 @@ class PopulationSamplingSpec extends AnyWordSpecLike with Matchers with BeamHelp agentsAfterSamplingOne should not equal agentsAfterSamplingTwo } - "sample different agents for different randomSeeds" in { + "sample different agents for different randomSeedForPopulationSampling" in { val samplingDataOne = getObjectsForPopulationSampling(1441) val samplingDataTwo = getObjectsForPopulationSampling(23) val agentsBeforeSamplingOneSize = samplingDataOne._1.getPopulation.getPersons.keySet().size() From 64c8c97c69e0b87ceb19144336b5c356c6a162ef Mon Sep 17 00:00:00 2001 From: GrigoryD Date: Sun, 24 Apr 2022 12:29:37 +0200 Subject: [PATCH 14/25] fix review comment --- .../scala/beam/sim/population/PopulationScaling.scala | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/scala/beam/sim/population/PopulationScaling.scala b/src/main/scala/beam/sim/population/PopulationScaling.scala index 0e7f71187ce..ba1e44d0dd1 100644 --- a/src/main/scala/beam/sim/population/PopulationScaling.scala +++ b/src/main/scala/beam/sim/population/PopulationScaling.scala @@ -125,11 +125,12 @@ class PopulationScaling extends LazyLogging { val numAgents = math.round( beamConfig.beam.agentsim.agentSampleSizeAsFractionOfPopulation * scenario.getPopulation.getPersons.size() ) - val rand = new Random(beamServices.beamConfig.beam.agentsim.maybeRandomSeedForPopulationSampling.getOrElse { - val seed = System.currentTimeMillis().toInt - logger.info("Agentsim maybeRandomSeedForPopulationSampling is set to {}.", seed) - seed - }) + + val seed = + beamServices.beamConfig.beam.agentsim.maybeRandomSeedForPopulationSampling.getOrElse(System.currentTimeMillis()) + logger.info("Agentsim maybeRandomSeedForPopulationSampling is set to {}.", seed) + val rand = new Random(seed) + val notSelectedHouseholdIds = mutable.Set[Id[Household]]() val notSelectedVehicleIds = mutable.Set[Id[Vehicle]]() val notSelectedPersonIds = mutable.Set[Id[Person]]() From 1dec074199cb6ad7333f10df13ad281b38f14574 Mon Sep 17 00:00:00 2001 From: GrigoryD Date: Sun, 24 Apr 2022 12:33:13 +0200 Subject: [PATCH 15/25] fix review comment 2 --- src/main/scala/beam/sim/population/PopulationScaling.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/beam/sim/population/PopulationScaling.scala b/src/main/scala/beam/sim/population/PopulationScaling.scala index ba1e44d0dd1..d0c4c2b9bbd 100644 --- a/src/main/scala/beam/sim/population/PopulationScaling.scala +++ b/src/main/scala/beam/sim/population/PopulationScaling.scala @@ -128,7 +128,7 @@ class PopulationScaling extends LazyLogging { val seed = beamServices.beamConfig.beam.agentsim.maybeRandomSeedForPopulationSampling.getOrElse(System.currentTimeMillis()) - logger.info("Agentsim maybeRandomSeedForPopulationSampling is set to {}.", seed) + logger.info("Agentsim randomSeedForPopulationSampling is set to {}.", seed) val rand = new Random(seed) val notSelectedHouseholdIds = mutable.Set[Id[Household]]() From 32a321d46f5ced4efdd96b56fcfff480692c29c6 Mon Sep 17 00:00:00 2001 From: GrigoryD Date: Sun, 24 Apr 2022 12:51:55 +0200 Subject: [PATCH 16/25] fix compile --- src/main/scala/beam/sim/population/PopulationScaling.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/beam/sim/population/PopulationScaling.scala b/src/main/scala/beam/sim/population/PopulationScaling.scala index d0c4c2b9bbd..970e1908292 100644 --- a/src/main/scala/beam/sim/population/PopulationScaling.scala +++ b/src/main/scala/beam/sim/population/PopulationScaling.scala @@ -127,7 +127,7 @@ class PopulationScaling extends LazyLogging { ) val seed = - beamServices.beamConfig.beam.agentsim.maybeRandomSeedForPopulationSampling.getOrElse(System.currentTimeMillis()) + beamServices.beamConfig.beam.agentsim.maybeRandomSeedForPopulationSampling.getOrElse(System.currentTimeMillis().toInt) logger.info("Agentsim randomSeedForPopulationSampling is set to {}.", seed) val rand = new Random(seed) From d95e9f952ad2d74424554bf0ae5d2a14cae2653c Mon Sep 17 00:00:00 2001 From: GrigoryD Date: Sun, 24 Apr 2022 12:58:59 +0200 Subject: [PATCH 17/25] scalafmt --- src/main/scala/beam/sim/population/PopulationScaling.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/scala/beam/sim/population/PopulationScaling.scala b/src/main/scala/beam/sim/population/PopulationScaling.scala index 970e1908292..1a796c7d6cb 100644 --- a/src/main/scala/beam/sim/population/PopulationScaling.scala +++ b/src/main/scala/beam/sim/population/PopulationScaling.scala @@ -127,7 +127,8 @@ class PopulationScaling extends LazyLogging { ) val seed = - beamServices.beamConfig.beam.agentsim.maybeRandomSeedForPopulationSampling.getOrElse(System.currentTimeMillis().toInt) + beamServices.beamConfig.beam.agentsim.maybeRandomSeedForPopulationSampling + .getOrElse(System.currentTimeMillis().toInt) logger.info("Agentsim randomSeedForPopulationSampling is set to {}.", seed) val rand = new Random(seed) From 5ac57cf2c84deb604a2982900fd4a59186e09e49 Mon Sep 17 00:00:00 2001 From: GrigoryD Date: Sun, 24 Apr 2022 14:36:07 +0200 Subject: [PATCH 18/25] fix review comment --- src/main/scala/beam/sim/config/BeamConfig.scala | 4 ++-- src/main/scala/beam/sim/population/PopulationScaling.scala | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/beam/sim/config/BeamConfig.scala b/src/main/scala/beam/sim/config/BeamConfig.scala index de62730f64b..2beab8edcdb 100644 --- a/src/main/scala/beam/sim/config/BeamConfig.scala +++ b/src/main/scala/beam/sim/config/BeamConfig.scala @@ -46,7 +46,7 @@ object BeamConfig { h3taz: BeamConfig.Beam.Agentsim.H3taz, lastIteration: scala.Int, populationAdjustment: java.lang.String, - maybeRandomSeedForPopulationSampling: scala.Option[scala.Int], + randomSeedForPopulationSampling: scala.Option[scala.Int], scenarios: BeamConfig.Beam.Agentsim.Scenarios, scheduleMonitorTask: BeamConfig.Beam.Agentsim.ScheduleMonitorTask, schedulerParallelismWindow: scala.Int, @@ -2185,7 +2185,7 @@ object BeamConfig { lastIteration = if (c.hasPathOrNull("lastIteration")) c.getInt("lastIteration") else 0, populationAdjustment = if (c.hasPathOrNull("populationAdjustment")) c.getString("populationAdjustment") else "DEFAULT_ADJUSTMENT", - maybeRandomSeedForPopulationSampling = + randomSeedForPopulationSampling = if (c.hasPathOrNull("randomSeedForPopulationSampling")) Some(c.getInt("randomSeedForPopulationSampling")) else None, scenarios = BeamConfig.Beam.Agentsim.Scenarios( diff --git a/src/main/scala/beam/sim/population/PopulationScaling.scala b/src/main/scala/beam/sim/population/PopulationScaling.scala index 1a796c7d6cb..3516ded40a9 100644 --- a/src/main/scala/beam/sim/population/PopulationScaling.scala +++ b/src/main/scala/beam/sim/population/PopulationScaling.scala @@ -127,7 +127,7 @@ class PopulationScaling extends LazyLogging { ) val seed = - beamServices.beamConfig.beam.agentsim.maybeRandomSeedForPopulationSampling + beamServices.beamConfig.beam.agentsim.randomSeedForPopulationSampling .getOrElse(System.currentTimeMillis().toInt) logger.info("Agentsim randomSeedForPopulationSampling is set to {}.", seed) val rand = new Random(seed) From b93def152ded5068df85cfb7bd84769c9ddaedf7 Mon Sep 17 00:00:00 2001 From: Dmitry Openkov Date: Mon, 25 Apr 2022 12:53:09 +0300 Subject: [PATCH 19/25] Added documentation for the second router (directory2). Removed osmFile since this param doesn't exist. --- docs/inputs.rst | 72 ++++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/docs/inputs.rst b/docs/inputs.rst index bff0f8f1ce5..5966eb28ae1 100755 --- a/docs/inputs.rst +++ b/docs/inputs.rst @@ -225,45 +225,46 @@ Routing Configuration ^^^^^^^^^^^^^^^^^^^^^ :: -# values: R5, staticGH, quasiDynamicGH, nativeCCH (Linux Only) -beam.routing.carRouter="R5" -beam.routing { - #Base local date in ISO 8061 YYYY-MM-DDTHH:MM:SS+HH:MM - baseDate = "2016-10-17T00:00:00-07:00" - transitOnStreetNetwork = true # PathTraversalEvents for transit vehicles - r5 { - directory = ${beam.inputDirectory}"/r5" - # 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 - travelTimeNoiseFraction = 0.0 - maxDistanceLimitByModeInMeters { - bike = 40000 + # values: R5, staticGH, quasiDynamicGH, nativeCCH (Linux Only) + beam.routing.carRouter="R5" + beam.routing { + #Base local date in ISO 8061 YYYY-MM-DDTHH:MM:SS+HH:MM + baseDate = "2016-10-17T00:00:00-07:00" + transitOnStreetNetwork = true # PathTraversalEvents for transit vehicles + r5 { + directory = ${beam.inputDirectory}"/r5" + directory2 = "String? |" + # Departure window in min + departureWindow = "double | 15.0" + numberOfSamples = "int | 1" + osmMapdbFile = ${beam.routing.r5.directory}"/osm.mapdb" + mNetBuilder.fromCRS = "EPSG:4326" # WGS84 + mNetBuilder.toCRS = "EPSG:26910" # UTM10N + travelTimeNoiseFraction = 0.0 + maxDistanceLimitByModeInMeters { + bike = 40000 + } + bikeLaneScaleFactor = 1.0 + bikeLaneLinkIdsFilePath = "" + } + startingIterationForTravelTimesMSA = 0 + overrideNetworkTravelTimesUsingSkims = false + + # Set a lower bound on travel times that can possibly be used to override the network-based + # travel time in the route.This is used to prevent unrealistically fast trips or negative + # duration trips. + minimumPossibleSkimBasedTravelTimeInS= 60 + skimTravelTimesScalingFactor = 0.0 + writeRoutingStatistic = false } - bikeLaneScaleFactor = 1.0 - bikeLaneLinkIdsFilePath = "" - } - startingIterationForTravelTimesMSA = 0 - overrideNetworkTravelTimesUsingSkims = false - - # Set a lower bound on travel times that can possibly be used to override the network-based - # travel time in the route.This is used to prevent unrealistically fast trips or negative - # duration trips. - minimumPossibleSkimBasedTravelTimeInS= 60 - skimTravelTimesScalingFactor = 0.0 - writeRoutingStatistic = false -} Parameters within beam.routing namespace -* carRouter: type of car router. The values are R5, staticGH, quasiDynamicGH, nativeCCH (Linux Only) where staticGH is GraphHopper router (when link travel times don't depend on time of the day), quasiDynamicGH is GraphHopper router (link -travel times depend on time of the day), nativeCCH is router that uses native CCH library. + +* carRouter: type of car router. The values are R5, staticGH, quasiDynamicGH, nativeCCH (Linux Only) where staticGH is GraphHopper router (when link travel times don't depend on time of the day), quasiDynamicGH is GraphHopper router (link travel times depend on time of the day), nativeCCH is router that uses native CCH library. * baseDate: the date which routes are requested on (transit depends on it) * transitOnStreetNetwork: if set to true transit PathTraversalEvents includes the route links -* r5.directory: the directory that contains R5 data which includes pbf file, GTFS files. +* r5.directory: the directory that contains R5 data which includes pbf file, GTFS files. If the directory contains multiple pbf files then a random file is loaded. +* r5.directory2: An optional directory that contains R5 data for the second router. It must contain the same pbf file and a subset of the GTFS files that are in the r5.directory (the first r5 directory). I.e. one can leave only the train GTFS file in the directory2. In this case train routes will be provided twice as much. But the first r5 directory must also contains the same train file or the second router will provide routes based on a different network which may lead to errors. * r5.departureWindow: the departure window for transit requests * r5.numberOfSamples: Number of Monte Carlo draws to take for frequency searches when doing routing * r5.osmMapdbFile: osm map db file that is stored to this location @@ -271,8 +272,7 @@ travel times depend on time of the day), nativeCCH is router that uses native CC * r5.mNetBuilder.toCRS: convert network coordinates to this CRS * r5.travelTimeNoiseFraction: if it's greater than zero some noise to link travel times will be added * r5.maxDistanceLimitByModeInMeters: one can limit max distance to be used for a particular mode -* r5.bikeLaneScaleFactor: this parameter is intended to make the links with bike lanes to be more preferable when the - router calculates a route for bikes. The less this scaleFactor the more preferable these links get +* r5.bikeLaneScaleFactor: this parameter is intended to make the links with bike lanes to be more preferable when the router calculates a route for bikes. The less this scaleFactor the more preferable these links get * r5.bikeLaneLinkIdsFilePath: the ids of links that have bike lanes * startingIterationForTravelTimesMSA: ??? * overrideNetworkTravelTimesUsingSkims: travel time is got from skims From 94ad66cf7b0f04af629070dd0581b1445c85e4c9 Mon Sep 17 00:00:00 2001 From: Alexander Vykhodtsev Date: Mon, 25 Apr 2022 20:12:12 +0600 Subject: [PATCH 20/25] Create and store network route for a person plan if it is empty --- .../agents/modalbehaviors/ChoosesMode.scala | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/main/scala/beam/agentsim/agents/modalbehaviors/ChoosesMode.scala b/src/main/scala/beam/agentsim/agents/modalbehaviors/ChoosesMode.scala index 04b85532a08..158e4affe4a 100755 --- a/src/main/scala/beam/agentsim/agents/modalbehaviors/ChoosesMode.scala +++ b/src/main/scala/beam/agentsim/agents/modalbehaviors/ChoosesMode.scala @@ -30,13 +30,16 @@ import beam.sim.{BeamServices, Geofence} import beam.utils.logging.pattern.ask import beam.utils.plan.sampling.AvailableModeUtils._ import org.matsim.api.core.v01.Id +import org.matsim.api.core.v01.network.Link import org.matsim.api.core.v01.population.{Activity, Leg} -import org.matsim.core.population.routes.NetworkRoute +import org.matsim.core.population.routes.{NetworkRoute, RouteUtils} import org.matsim.core.utils.misc.Time import java.util.concurrent.atomic.AtomicReference +import scala.collection.JavaConverters import scala.concurrent.duration._ import scala.concurrent.{ExecutionContext, Future} +import scala.jdk.CollectionConverters.asJavaIterableConverter /** * BEAM @@ -739,6 +742,29 @@ trait ChoosesMode { routingFinished = true ) } + + // If person plan doesn't have a route for an activity create and save it + for { + activity <- nextActivity(choosesModeData.personData) + leg <- _experiencedBeamPlan.getTripContaining(activity).leg if leg.getRoute == null + } yield { + val links = + response.itineraries + .flatMap(_.beamLegs) + .find(_.mode == BeamMode.CAR) + .map { beamLeg => + beamLeg.travelPath.linkIds + .map(id => Id.create(id, classOf[Link])) + .toList + } + .getOrElse(List.empty) + + if (links.nonEmpty) { + val route = RouteUtils.createNetworkRoute(JavaConverters.seqAsJavaList(links), beamScenario.network) + leg.setRoute(route) + } + } + stay() using newData case Event(theRideHailResult: RideHailResponse, choosesModeData: ChoosesModeData) => From 85c5bd6be7def5365d71fea1727528870add0af7 Mon Sep 17 00:00:00 2001 From: Dmitry Openkov Date: Wed, 27 Apr 2022 18:58:38 +0300 Subject: [PATCH 21/25] Fixes after merging --- .../ParallelParkingManagerSpec.scala | 14 ++++++------- .../ZonalParkingManagerSpec.scala | 20 ++++++++++--------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/test/scala/beam/agentsim/infrastructure/ParallelParkingManagerSpec.scala b/src/test/scala/beam/agentsim/infrastructure/ParallelParkingManagerSpec.scala index 8ffb341e0d4..aeafa30a24e 100644 --- a/src/test/scala/beam/agentsim/infrastructure/ParallelParkingManagerSpec.scala +++ b/src/test/scala/beam/agentsim/infrastructure/ParallelParkingManagerSpec.scala @@ -362,9 +362,9 @@ class ParallelParkingManagerSpec zpm, new Coord(170308.0, 2964.0), "4", - ParkingZone.createId("73"), + ParkingZone.createId("82"), FlatFee(0.0), - ParkingType.Residential, + ParkingType.Public, VehicleManager.AnyManager ) @@ -372,9 +372,9 @@ class ParallelParkingManagerSpec zpm, new Coord(166321.0, 1568.0), "1", - ParkingZone.createId("22"), + ParkingZone.createId("80"), FlatFee(0.0), - ParkingType.Residential, + ParkingType.Public, VehicleManager.AnyManager ) @@ -382,9 +382,9 @@ class ParallelParkingManagerSpec zpm, new Coord(167141.3, 3326.017), "2", - ParkingZone.createId("15"), - Block(0.0, 3600), - ParkingType.Residential, + ParkingZone.createId("115"), + FlatFee(0.0), + ParkingType.Public, VehicleManager.AnyManager ) } diff --git a/src/test/scala/beam/agentsim/infrastructure/ZonalParkingManagerSpec.scala b/src/test/scala/beam/agentsim/infrastructure/ZonalParkingManagerSpec.scala index 6fd345bb429..28d899d2317 100644 --- a/src/test/scala/beam/agentsim/infrastructure/ZonalParkingManagerSpec.scala +++ b/src/test/scala/beam/agentsim/infrastructure/ZonalParkingManagerSpec.scala @@ -336,9 +336,9 @@ class ZonalParkingManagerSpec zpm, SpaceTime(new Coord(170308.0, 2964.0), 0), "4", - ParkingZone.createId("73"), + ParkingZone.createId("82"), FlatFee(0.0), - ParkingType.Residential, + ParkingType.Public, "beamVilleCar" ) @@ -346,9 +346,9 @@ class ZonalParkingManagerSpec zpm, SpaceTime(new Coord(166321.0, 1568.0), 0), "1", - ParkingZone.createId("22"), + ParkingZone.createId("80"), FlatFee(0.0), - ParkingType.Residential, + ParkingType.Public, "beamVilleCar" ) @@ -356,9 +356,9 @@ class ZonalParkingManagerSpec zpm, SpaceTime(new Coord(167141.3, 3326.017), 0), "2", - ParkingZone.createId("15"), - Block(0.0, 3600), - ParkingType.Residential, + ParkingZone.createId("115"), + FlatFee(0.0), + ParkingType.Public, "beamVilleCar" ) @@ -440,6 +440,8 @@ class ZonalParkingManagerSpec boundingBox, beamConfig.beam.agentsim.agents.parking.minSearchRadius, beamConfig.beam.agentsim.agents.parking.maxSearchRadius, + beamConfig.beam.agentsim.agents.parking.fractionOfSameTypeZones, + beamConfig.beam.agentsim.agents.parking.minNumberOfSameTypeZones, randomSeed, beamConfig.beam.agentsim.agents.parking.mulitnomialLogit ) @@ -448,8 +450,8 @@ class ZonalParkingManagerSpec zonesMap, SpaceTime(new Coord(170308.0, 2964.0), 0), "4", - ParkingZone.createId("73"), - FlatFee(1.99), + ParkingZone.createId("105"), + Block(1.99, 3600), ParkingType.Residential, "beamVilleCar" ) From e7beec012de160b1aeba988ecec1a4ce0258607e Mon Sep 17 00:00:00 2001 From: Alexander Vykhodtsev Date: Thu, 28 Apr 2022 19:41:19 +0600 Subject: [PATCH 22/25] No need for yield --- .../scala/beam/agentsim/agents/modalbehaviors/ChoosesMode.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/beam/agentsim/agents/modalbehaviors/ChoosesMode.scala b/src/main/scala/beam/agentsim/agents/modalbehaviors/ChoosesMode.scala index 158e4affe4a..d2dc56b51f5 100755 --- a/src/main/scala/beam/agentsim/agents/modalbehaviors/ChoosesMode.scala +++ b/src/main/scala/beam/agentsim/agents/modalbehaviors/ChoosesMode.scala @@ -747,7 +747,7 @@ trait ChoosesMode { for { activity <- nextActivity(choosesModeData.personData) leg <- _experiencedBeamPlan.getTripContaining(activity).leg if leg.getRoute == null - } yield { + } { val links = response.itineraries .flatMap(_.beamLegs) From c2b5023b458a7c7c29531030fbe4cd75f9bb40fa Mon Sep 17 00:00:00 2001 From: Dmitry Openkov Date: Thu, 5 May 2022 12:00:24 +0300 Subject: [PATCH 23/25] Removed link level parking. Also, a type parameter identifier [GEO] was removed from the parking classes. --- .../infrastructure/GeometryPerformance.scala | 2 +- src/main/resources/beam-template.conf | 4 +- .../DefaultRideHailDepotParkingManager.scala | 58 ++-- .../RideHailDepotParkingManager.scala | 8 +- .../agents/ridehail/RideHailManager.scala | 2 +- .../infrastructure/ChargingFunctions.scala | 44 ++- .../infrastructure/ChargingNetwork.scala | 65 ++--- .../ChargingNetworkManager.scala | 14 +- .../DefaultRidehailFunctions.scala | 51 ++-- .../HierarchicalParkingManager.scala | 264 +++++++----------- .../InfrastructureFunctions.scala | 70 +++-- .../infrastructure/InfrastructureUtils.scala | 108 +++---- .../ParallelParkingManager.scala | 31 +- .../infrastructure/ParkingFunctions.scala | 47 ++-- .../ParkingManagerBenchmark.scala | 99 ++----- .../ParkingNetworkManager.scala | 4 +- .../infrastructure/ParkingStall.scala | 26 +- .../infrastructure/ZonalParkingManager.scala | 80 ++---- .../infrastructure/parking/GeoLevel.scala | 75 ----- .../parking/LinkLevelOperations.scala | 27 -- .../parking/ParkingNetwork.scala | 5 +- .../parking/ParkingStallSampling.scala | 1 - .../infrastructure/parking/ParkingZone.scala | 47 ++-- .../parking/ParkingZoneFileUtils.scala | 155 ++++------ .../parking/ParkingZoneSearch.scala | 99 ++++--- .../parking/TazToLinkLevelParkingApp.scala | 80 ------ .../power/SitePowerManager.scala | 2 +- .../agentsim/infrastructure/taz/TAZ.scala | 2 + src/main/scala/beam/sim/BeamHelper.scala | 8 - src/main/scala/beam/sim/BeamScenario.scala | 3 - src/main/scala/beam/sim/common/GeoUtils.scala | 28 ++ .../scala/beam/sim/config/BeamConfig.scala | 2 - .../sim/metrics/BeamStaticMetricsWriter.scala | 4 +- .../agents/PersonAndTransitDriverSpec.scala | 2 +- .../ChargingNetworkManagerSpec.scala | 1 - .../infrastructure/ChargingNetworkSpec.scala | 6 +- .../HierarchicalParkingManagerSpec.scala | 46 +-- .../HierarchicalParkingManagerUtilSpec.scala | 61 +--- .../ParallelParkingManagerSpec.scala | 31 +- .../ParallelParkingManagerUtilSpec.scala | 2 +- .../ZonalParkingManagerSpec.scala | 30 +- .../parking/ParkingZoneFileUtilsSpec.scala | 92 ++---- .../power/PowerControllerSpec.scala | 8 +- .../power/SitePowerManagerSpec.scala | 8 +- .../scala/beam/router/BeamRouterSpec.scala | 3 - .../beam/utils/BeamScenarioForTest.scala | 3 - src/test/scala/beam/utils/GeoUtilsTest.scala | 21 ++ test/input/beamville/parking/link-parking.csv | 3 - test/input/sf-light/link-parking.csv.gz | 3 - ...t-1k-csv-linkparking-pickups-dropoffs.conf | 18 -- .../sf-light/sf-light-25k-experiment-2.conf | 9 - .../sf-light/sf-light-25k-experiment-3.conf | 13 - .../sf-light/sf-light-25k-experiment-4.conf | 12 - .../sf-light/sf-light-25k-experiment-5.conf | 12 - 54 files changed, 614 insertions(+), 1285 deletions(-) delete mode 100644 src/main/scala/beam/agentsim/infrastructure/parking/GeoLevel.scala delete mode 100644 src/main/scala/beam/agentsim/infrastructure/parking/LinkLevelOperations.scala delete mode 100644 src/main/scala/beam/agentsim/infrastructure/parking/TazToLinkLevelParkingApp.scala delete mode 100644 test/input/beamville/parking/link-parking.csv delete mode 100644 test/input/sf-light/link-parking.csv.gz delete mode 100755 test/input/sf-light/sf-light-1k-csv-linkparking-pickups-dropoffs.conf delete mode 100755 test/input/sf-light/sf-light-25k-experiment-2.conf delete mode 100755 test/input/sf-light/sf-light-25k-experiment-3.conf delete mode 100755 test/input/sf-light/sf-light-25k-experiment-4.conf delete mode 100755 test/input/sf-light/sf-light-25k-experiment-5.conf diff --git a/src/jmh/scala/beam/agentsim/infrastructure/GeometryPerformance.scala b/src/jmh/scala/beam/agentsim/infrastructure/GeometryPerformance.scala index 129fb574c73..b095bdcdaa9 100644 --- a/src/jmh/scala/beam/agentsim/infrastructure/GeometryPerformance.scala +++ b/src/jmh/scala/beam/agentsim/infrastructure/GeometryPerformance.scala @@ -75,7 +75,7 @@ object GeometryPerformance { val baseConfigUnresolved = ConfigFactory.parseString("config=" + configLocation) val baseConfig = baseConfigUnresolved.resolve() val beamConfig = BeamConfig(baseConfig) - val stalls = InfrastructureUtils.loadStalls[TAZ]( + val stalls = InfrastructureUtils.loadStalls( s"$beamHome/test/input/sf-bay/parking/taz-parking-unlimited-fast-limited-l2-150-baseline.csv", IndexedSeq(), tazMap.tazQuadTree, //it is required only in case of failures diff --git a/src/main/resources/beam-template.conf b/src/main/resources/beam-template.conf index 5fe0b3585f1..30d26f75bd6 100755 --- a/src/main/resources/beam-template.conf +++ b/src/main/resources/beam-template.conf @@ -177,10 +177,8 @@ beam.agentsim.taz.filePath = ${beam.inputDirectory}"/taz-centers.csv" beam.agentsim.taz.parkingFilePath = "" beam.agentsim.taz.parkingStallCountScalingFactor = "double | 1.0" beam.agentsim.taz.parkingCostScalingFactor = "double | 1.0" -# options: DEFAULT, HIERARCHICAL, PARALLEL, HIERARCHICAL requires link parking file +# options: DEFAULT, HIERARCHICAL, PARALLEL beam.agentsim.taz.parkingManager.method = "String | DEFAULT" -# options: TAZ, Link (Link level can work only with DEFAULT parking manager) -beam.agentsim.taz.parkingManager.level = "TAZ" beam.agentsim.taz.parkingManager.displayPerformanceTimings = false beam.agentsim.taz.parkingManager.parallel.numberOfClusters = "int | 8" #Toll params diff --git a/src/main/scala/beam/agentsim/agents/ridehail/DefaultRideHailDepotParkingManager.scala b/src/main/scala/beam/agentsim/agents/ridehail/DefaultRideHailDepotParkingManager.scala index 63d718c77a5..b0305eff483 100644 --- a/src/main/scala/beam/agentsim/agents/ridehail/DefaultRideHailDepotParkingManager.scala +++ b/src/main/scala/beam/agentsim/agents/ridehail/DefaultRideHailDepotParkingManager.scala @@ -15,7 +15,6 @@ import beam.sim.{BeamServices, Geofence} import beam.utils.logging.LogActorState import com.vividsolutions.jts.geom.Envelope import org.matsim.api.core.v01.Id -import org.matsim.api.core.v01.network.Link import org.matsim.core.controler.OutputDirectoryHierarchy import org.matsim.core.utils.collections.QuadTree @@ -42,12 +41,12 @@ import scala.collection.mutable.ListBuffer * 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" // 60 minute penalty if out of range */ -class DefaultRideHailDepotParkingManager[GEO: GeoLevel]( +class DefaultRideHailDepotParkingManager( vehicleManagerId: Id[VehicleManager], - parkingZones: Map[Id[ParkingZoneId], ParkingZone[GEO]], + parkingZones: Map[Id[ParkingZoneId], ParkingZone], outputDirectory: OutputDirectoryHierarchy, rideHailConfig: BeamConfig.Beam.Agentsim.Agents.RideHail -) extends RideHailDepotParkingManager[GEO](parkingZones) { +) extends RideHailDepotParkingManager(parkingZones) { /* * All internal data to track Depots, ParkingZones, and charging queues are kept in ParkingZoneDepotData which is @@ -59,7 +58,7 @@ class DefaultRideHailDepotParkingManager[GEO: GeoLevel]( parkingZoneIdToParkingZoneDepotData.put(parkingZoneId, ParkingZoneDepotData.empty) } - override protected val searchFunctions: Option[InfrastructureFunctions[GEO]] = None + override protected val searchFunctions: Option[InfrastructureFunctions] = None protected val chargingPlugTypesSortedByPower = parkingZones .flatMap(_._2.chargingPointType) @@ -92,9 +91,9 @@ class DefaultRideHailDepotParkingManager[GEO: GeoLevel]( /* * Track "Depots" as a mapping from TAZ Id to ParkingZones to facilitate processing all ParkingZones in a depot */ - val tazIdToParkingZones: mutable.Map[Id[GEO], Map[Id[ParkingZoneId], ParkingZone[GEO]]] = - mutable.Map.empty[Id[GEO], Map[Id[ParkingZoneId], ParkingZone[GEO]]] - parkingZones.groupBy(_._2.geoId).foreach(tup => tazIdToParkingZones += tup) + val tazIdToParkingZones: mutable.Map[Id[TAZ], Map[Id[ParkingZoneId], ParkingZone]] = + mutable.Map.empty[Id[TAZ], Map[Id[ParkingZoneId], ParkingZone]] + parkingZones.groupBy(_._2.tazId).foreach(tup => tazIdToParkingZones += tup) def registerGeofences(vehicleIdToGeofenceMap: mutable.Map[VehicleId, Option[Geofence]]) = { vehicleIdToGeofenceMap.foreach { @@ -346,26 +345,24 @@ object DefaultRideHailDepotParkingManager { val MinNumberOfSameTypeZones: Int = 5 val outputRidehailParkingFileName = "ridehailParking.csv" - def apply[GEO: GeoLevel]( + def apply( vehicleManagerId: Id[VehicleManager], - parkingZones: Map[Id[ParkingZoneId], ParkingZone[GEO]], - geoQuadTree: QuadTree[GEO], - idToGeoMapping: scala.collection.Map[Id[GEO], GEO], - geoToTAZ: GEO => TAZ, + parkingZones: Map[Id[ParkingZoneId], ParkingZone], + geoQuadTree: QuadTree[TAZ], + idToGeoMapping: scala.collection.Map[Id[TAZ], TAZ], boundingBox: Envelope, beamServices: BeamServices - ): RideHailDepotParkingManager[GEO] = { - new DefaultRideHailDepotParkingManager[GEO]( + ): RideHailDepotParkingManager = { + new DefaultRideHailDepotParkingManager( vehicleManagerId, parkingZones, beamServices.matsimServices.getControlerIO, beamServices.beamConfig.beam.agentsim.agents.rideHail ) { - override val searchFunctions: Option[InfrastructureFunctions[GEO]] = Some( + override val searchFunctions: Option[InfrastructureFunctions] = Some( new DefaultRidehailFunctions( geoQuadTree, idToGeoMapping, - geoToTAZ, parkingZones, parkingZoneIdToParkingZoneDepotData, beamServices.geo.distUTMInMeters, @@ -385,36 +382,15 @@ object DefaultRideHailDepotParkingManager { def init( vehicleManagerId: Id[VehicleManager], - parkingZones: Map[Id[ParkingZoneId], ParkingZone[TAZ]], + parkingZones: Map[Id[ParkingZoneId], ParkingZone], boundingBox: Envelope, beamServices: BeamServices - ): RideHailDepotParkingManager[TAZ] = { - DefaultRideHailDepotParkingManager[TAZ]( + ): RideHailDepotParkingManager = { + DefaultRideHailDepotParkingManager( vehicleManagerId, parkingZones, beamServices.beamScenario.tazTreeMap.tazQuadTree, beamServices.beamScenario.tazTreeMap.idToTAZMapping, - identity[TAZ], - boundingBox, - beamServices - ) - } - - def init( - vehicleManagerId: Id[VehicleManager], - parkingZones: Map[Id[ParkingZoneId], ParkingZone[Link]], - geoQuadTree: QuadTree[Link], - idToGeoMapping: scala.collection.Map[Id[Link], Link], - geoToTAZ: Link => TAZ, - boundingBox: Envelope, - beamServices: BeamServices - ): RideHailDepotParkingManager[Link] = { - DefaultRideHailDepotParkingManager[Link]( - vehicleManagerId, - parkingZones, - geoQuadTree, - idToGeoMapping, - geoToTAZ, boundingBox, beamServices ) diff --git a/src/main/scala/beam/agentsim/agents/ridehail/RideHailDepotParkingManager.scala b/src/main/scala/beam/agentsim/agents/ridehail/RideHailDepotParkingManager.scala index 350921e8589..4be1d5aeec4 100644 --- a/src/main/scala/beam/agentsim/agents/ridehail/RideHailDepotParkingManager.scala +++ b/src/main/scala/beam/agentsim/agents/ridehail/RideHailDepotParkingManager.scala @@ -4,21 +4,21 @@ import beam.agentsim.Resource.ReleaseParkingStall import beam.agentsim.agents.ridehail.ParkingZoneDepotData.ChargingQueueEntry import beam.agentsim.agents.ridehail.RideHailManager.VehicleId import beam.agentsim.agents.vehicles.BeamVehicle -import beam.agentsim.infrastructure.parking.{GeoLevel, ParkingZone, ParkingZoneId} +import beam.agentsim.infrastructure.parking.{ParkingZone, ParkingZoneId} import beam.agentsim.infrastructure.{ChargingNetwork, ParkingStall} import beam.sim.{BeamServices, Geofence} import org.matsim.api.core.v01.Id import scala.collection.mutable -abstract class RideHailDepotParkingManager[GEO: GeoLevel](parkingZones: Map[Id[ParkingZoneId], ParkingZone[GEO]]) - extends ChargingNetwork[GEO](parkingZones) { +abstract class RideHailDepotParkingManager(parkingZones: Map[Id[ParkingZoneId], ParkingZone]) + extends ChargingNetwork(parkingZones) { override def processReleaseParkingStall(release: ReleaseParkingStall): Boolean = { if (!parkingZones.contains(release.stall.parkingZoneId)) { false } else { - val parkingZone: ParkingZone[GEO] = parkingZones(release.stall.parkingZoneId) + val parkingZone: ParkingZone = parkingZones(release.stall.parkingZoneId) val success = searchFunctions.get.releaseStall(parkingZone) if (success) { totalStallsInUse -= 1 diff --git a/src/main/scala/beam/agentsim/agents/ridehail/RideHailManager.scala b/src/main/scala/beam/agentsim/agents/ridehail/RideHailManager.scala index 65ae340898f..eed2cb24485 100755 --- a/src/main/scala/beam/agentsim/agents/ridehail/RideHailManager.scala +++ b/src/main/scala/beam/agentsim/agents/ridehail/RideHailManager.scala @@ -231,7 +231,7 @@ class RideHailManager( val tncIterationStats: Option[TNCIterationStats], val routeHistory: RouteHistory, val rideHailFleetInitializer: RideHailFleetInitializer, - val rideHailParkingNetwork: RideHailDepotParkingManager[_] + val rideHailParkingNetwork: RideHailDepotParkingManager ) extends LoggingMessageActor with ActorLogging with Stash { diff --git a/src/main/scala/beam/agentsim/infrastructure/ChargingFunctions.scala b/src/main/scala/beam/agentsim/infrastructure/ChargingFunctions.scala index 7a7d1f58234..fcfd52b36c6 100644 --- a/src/main/scala/beam/agentsim/infrastructure/ChargingFunctions.scala +++ b/src/main/scala/beam/agentsim/infrastructure/ChargingFunctions.scala @@ -16,11 +16,10 @@ import org.matsim.core.utils.collections.QuadTree import scala.util.Random -class ChargingFunctions[GEO: GeoLevel]( - geoQuadTree: QuadTree[GEO], - idToGeoMapping: scala.collection.Map[Id[GEO], GEO], - geoToTAZ: GEO => TAZ, - parkingZones: Map[Id[ParkingZoneId], ParkingZone[GEO]], +class ChargingFunctions( + geoQuadTree: QuadTree[TAZ], + idToGeoMapping: scala.collection.Map[Id[TAZ], TAZ], + parkingZones: Map[Id[ParkingZoneId], ParkingZone], distanceFunction: (Coord, Coord) => Double, minSearchRadius: Double, maxSearchRadius: Double, @@ -33,10 +32,9 @@ class ChargingFunctions[GEO: GeoLevel]( mnlParkingConfig: BeamConfig.Beam.Agentsim.Agents.Parking.MulitnomialLogit, skims: Option[Skims], fuelPrice: Map[FuelType, Double] -) extends ParkingFunctions[GEO]( +) extends ParkingFunctions( geoQuadTree, idToGeoMapping, - geoToTAZ, parkingZones, distanceFunction, minSearchRadius, @@ -56,7 +54,7 @@ class ChargingFunctions[GEO: GeoLevel]( * @param inquiry ParkingInquiry * @return */ - def ifRideHailCurrentlyOnShiftThenFastChargingOnly(zone: ParkingZone[GEO], inquiry: ParkingInquiry): Boolean = { + def ifRideHailCurrentlyOnShiftThenFastChargingOnly(zone: ParkingZone, inquiry: ParkingInquiry): Boolean = { inquiry.reservedFor match { case VehicleManager.TypeEnum.RideHail if inquiry.parkingDuration <= 3600 => ChargingPointType.isFastCharger(zone.chargingPointType.get) @@ -71,7 +69,7 @@ class ChargingFunctions[GEO: GeoLevel]( * @param inquiry ParkingInquiry * @return */ - def ifEnrouteThenFastChargingOnly(zone: ParkingZone[GEO], inquiry: ParkingInquiry): Boolean = { + def ifEnrouteThenFastChargingOnly(zone: ParkingZone, inquiry: ParkingInquiry): Boolean = { inquiry.searchMode match { case ParkingSearchMode.EnRoute => ChargingPointType.isFastCharger(zone.chargingPointType.get) @@ -86,7 +84,7 @@ class ChargingFunctions[GEO: GeoLevel]( * @param beamVehicleMaybe Option[BeamVehicle] * @return */ - def hasValidChargingCapability(zone: ParkingZone[GEO], beamVehicleMaybe: Option[BeamVehicle]): Boolean = { + def hasValidChargingCapability(zone: ParkingZone, beamVehicleMaybe: Option[BeamVehicle]): Boolean = { beamVehicleMaybe.forall( _.beamVehicleType.chargingCapability.forall(getPower(_) >= getPower(zone.chargingPointType.get)) ) @@ -103,7 +101,7 @@ class ChargingFunctions[GEO: GeoLevel]( * @return */ override protected def setupSearchFilterPredicates( - zone: ParkingZone[GEO], + zone: ParkingZone, inquiry: ParkingInquiry ): Boolean = { if (zone.chargingPointType.isEmpty) @@ -124,7 +122,7 @@ class ChargingFunctions[GEO: GeoLevel]( * @return */ override protected def setupMNLParameters( - parkingAlternative: ParkingAlternative[GEO], + parkingAlternative: ParkingAlternative, inquiry: ParkingInquiry ): Map[ParkingMNL.Parameters, Double] = { val parkingParameters = inquiry.searchMode match { @@ -149,12 +147,12 @@ class ChargingFunctions[GEO: GeoLevel]( /** * Generic method that specifies the behavior when MNL returns a ParkingZoneSearchResult - * @param parkingZoneSearchResult ParkingZoneSearchResult[GEO] + * @param parkingZoneSearchResult ParkingZoneSearchResult */ override protected def processParkingZoneSearchResult( inquiry: ParkingInquiry, - parkingZoneSearchResult: Option[ParkingZoneSearchResult[GEO]] - ): Option[ParkingZoneSearchResult[GEO]] = parkingZoneSearchResult match { + parkingZoneSearchResult: Option[ParkingZoneSearchResult] + ): Option[ParkingZoneSearchResult] = parkingZoneSearchResult match { case None if inquiry.searchMode == ParkingSearchMode.EnRoute => // did not find a stall with a fast charging point, return a dummy stall Some( @@ -166,9 +164,7 @@ class ChargingFunctions[GEO: GeoLevel]( inquiry.originUtm.get.loc.getY + 2000, inquiry.originUtm.get.loc.getY - 2000 ), - new Random(seed), - tazId = TAZ.EmergencyTAZId, - geoId = GeoLevel[GEO].emergencyGeoId + new Random(seed) ), DefaultParkingZone ) @@ -177,19 +173,19 @@ class ChargingFunctions[GEO: GeoLevel]( } /** - * sample location of a parking stall with a GEO area + * sample location of a parking stall with a TAZ area * * @param inquiry ParkingInquiry - * @param parkingZone ParkingZone[GEO] - * @param geoArea GEO + * @param parkingZone ParkingZone + * @param taz TAZ * @return */ override protected def sampleParkingStallLocation( inquiry: ParkingInquiry, - parkingZone: ParkingZone[GEO], - geoArea: GEO, + parkingZone: ParkingZone, + taz: TAZ, inClosestZone: Boolean = false - ): Coord = super[ParkingFunctions].sampleParkingStallLocation(inquiry, parkingZone, geoArea, inClosestZone) + ): Coord = super[ParkingFunctions].sampleParkingStallLocation(inquiry, parkingZone, taz, inClosestZone) /** * getTravelTime diff --git a/src/main/scala/beam/agentsim/infrastructure/ChargingNetwork.scala b/src/main/scala/beam/agentsim/infrastructure/ChargingNetwork.scala index d98f303f898..2b7f372e382 100644 --- a/src/main/scala/beam/agentsim/infrastructure/ChargingNetwork.scala +++ b/src/main/scala/beam/agentsim/infrastructure/ChargingNetwork.scala @@ -24,11 +24,10 @@ import scala.util.Random /** * Created by haitamlaarabi */ -class ChargingNetwork[GEO: GeoLevel](val chargingZones: Map[Id[ParkingZoneId], ParkingZone[GEO]]) - extends ParkingNetwork[GEO](chargingZones) { +class ChargingNetwork(val chargingZones: Map[Id[ParkingZoneId], ParkingZone]) extends ParkingNetwork(chargingZones) { import ChargingNetwork._ - override protected val searchFunctions: Option[InfrastructureFunctions[GEO]] = None + override protected val searchFunctions: Option[InfrastructureFunctions] = None protected val beamVehicleIdToChargingVehicleMap: mutable.HashMap[Id[BeamVehicle], ChargingVehicle] = mutable.HashMap.empty @@ -151,23 +150,21 @@ object ChargingNetwork extends LazyLogging { val WaitingAtStation, Connected, Disconnected, GracePeriod = Value } - def apply[GEO: GeoLevel]( - chargingZones: Map[Id[ParkingZoneId], ParkingZone[GEO]], - geoQuadTree: QuadTree[GEO], - idToGeoMapping: scala.collection.Map[Id[GEO], GEO], - geoToTAZ: GEO => TAZ, + def apply( + chargingZones: Map[Id[ParkingZoneId], ParkingZone], + geoQuadTree: QuadTree[TAZ], + idToGeoMapping: scala.collection.Map[Id[TAZ], TAZ], envelopeInUTM: Envelope, beamConfig: BeamConfig, distanceFunction: (Coord, Coord) => Double, skims: Option[Skims], fuelPrice: Map[FuelType, Double] - ): ChargingNetwork[GEO] = { - new ChargingNetwork[GEO](chargingZones) { - override val searchFunctions: Option[InfrastructureFunctions[GEO]] = Some( - new ChargingFunctions[GEO]( + ): ChargingNetwork = { + new ChargingNetwork(chargingZones) { + override val searchFunctions: Option[InfrastructureFunctions] = Some( + new ChargingFunctions( geoQuadTree, idToGeoMapping, - geoToTAZ, chargingZones, distanceFunction, beamConfig.beam.agentsim.agents.parking.minSearchRadius, @@ -186,18 +183,17 @@ object ChargingNetwork extends LazyLogging { } } - def apply[GEO: GeoLevel]( + def apply( parkingDescription: Iterator[String], - geoQuadTree: QuadTree[GEO], - idToGeoMapping: scala.collection.Map[Id[GEO], GEO], - geoToTAZ: GEO => TAZ, + geoQuadTree: QuadTree[TAZ], + idToGeoMapping: scala.collection.Map[Id[TAZ], TAZ], envelopeInUTM: Envelope, beamConfig: BeamConfig, beamServicesMaybe: Option[BeamServices], distanceFunction: (Coord, Coord) => Double, skims: Option[Skims] = None, fuelPrice: Map[FuelType, Double] = Map() - ): ChargingNetwork[GEO] = { + ): ChargingNetwork = { val parking = ParkingZoneFileUtils.fromIterator( parkingDescription, Some(beamConfig), @@ -207,11 +203,10 @@ object ChargingNetwork extends LazyLogging { 1.0, 1.0 ) - ChargingNetwork[GEO]( + ChargingNetwork( parking.zones.toMap, geoQuadTree, idToGeoMapping, - geoToTAZ, envelopeInUTM, beamConfig, distanceFunction, @@ -221,15 +216,14 @@ object ChargingNetwork extends LazyLogging { } def init( - chargingZones: Map[Id[ParkingZoneId], ParkingZone[TAZ]], + chargingZones: Map[Id[ParkingZoneId], ParkingZone], envelopeInUTM: Envelope, beamServices: BeamServices - ): ChargingNetwork[TAZ] = { - ChargingNetwork[TAZ]( + ): ChargingNetwork = { + ChargingNetwork( chargingZones, beamServices.beamScenario.tazTreeMap.tazQuadTree, beamServices.beamScenario.tazTreeMap.idToTAZMapping, - identity[TAZ](_), envelopeInUTM, beamServices.beamConfig, beamServices.geo.distUTMInMeters(_, _), @@ -238,28 +232,7 @@ object ChargingNetwork extends LazyLogging { ) } - def init( - chargingZones: Map[Id[ParkingZoneId], ParkingZone[Link]], - geoQuadTree: QuadTree[Link], - idToGeoMapping: scala.collection.Map[Id[Link], Link], - geoToTAZ: Link => TAZ, - envelopeInUTM: Envelope, - beamServices: BeamServices - ): ChargingNetwork[Link] = { - ChargingNetwork[Link]( - chargingZones, - geoQuadTree, - idToGeoMapping, - geoToTAZ, - envelopeInUTM, - beamServices.beamConfig, - beamServices.geo.distUTMInMeters(_, _), - Some(beamServices.skims), - beamServices.beamScenario.fuelTypePrices - ) - } - - final case class ChargingStation(zone: ParkingZone[_]) { + final case class ChargingStation(zone: ParkingZone) { import ChargingStatus._ private val chargingVehiclesInternal = mutable.HashMap.empty[Id[BeamVehicle], ChargingVehicle] diff --git a/src/main/scala/beam/agentsim/infrastructure/ChargingNetworkManager.scala b/src/main/scala/beam/agentsim/infrastructure/ChargingNetworkManager.scala index 51b198671a4..0784885cf03 100644 --- a/src/main/scala/beam/agentsim/infrastructure/ChargingNetworkManager.scala +++ b/src/main/scala/beam/agentsim/infrastructure/ChargingNetworkManager.scala @@ -34,8 +34,8 @@ import scala.language.postfixOps class ChargingNetworkManager( beamServices: BeamServices, - chargingNetwork: ChargingNetwork[_], - rideHailNetwork: ChargingNetwork[_], + chargingNetwork: ChargingNetwork, + rideHailNetwork: ChargingNetwork, parkingNetworkManager: ActorRef, scheduler: ActorRef ) extends LoggingMessageActor @@ -277,15 +277,15 @@ object ChargingNetworkManager extends LazyLogging { def props( beamServices: BeamServices, - chargingNetwork: ChargingNetwork[_], - rideHailNetwork: ChargingNetwork[_], + chargingNetwork: ChargingNetwork, + rideHailNetwork: ChargingNetwork, parkingManager: ActorRef, scheduler: ActorRef ): Props = { Props(new ChargingNetworkManager(beamServices, chargingNetwork, rideHailNetwork, parkingManager, scheduler)) } - case class ChargingNetworkHelper(chargingNetwork: ChargingNetwork[_], rideHailNetwork: ChargingNetwork[_]) { + case class ChargingNetworkHelper(chargingNetwork: ChargingNetwork, rideHailNetwork: ChargingNetwork) { lazy val allChargingStations: List[ChargingStation] = chargingNetwork.chargingStations ++ rideHailNetwork.chargingStations @@ -294,7 +294,7 @@ object ChargingNetworkManager extends LazyLogging { * @param managerId vehicle manager id * @return */ - def get(managerId: Id[VehicleManager]): ChargingNetwork[_] = { + def get(managerId: Id[VehicleManager]): ChargingNetwork = { get(VehicleManager.getReservedFor(managerId).get) } @@ -302,7 +302,7 @@ object ChargingNetworkManager extends LazyLogging { * @param managerType vehicle manager type * @return */ - def get(managerType: ReservedFor): ChargingNetwork[_] = { + def get(managerType: ReservedFor): ChargingNetwork = { managerType match { case VehicleManager.TypeEnum.RideHail => rideHailNetwork case _ => chargingNetwork diff --git a/src/main/scala/beam/agentsim/infrastructure/DefaultRidehailFunctions.scala b/src/main/scala/beam/agentsim/infrastructure/DefaultRidehailFunctions.scala index cd16aeefc3f..fb660389885 100644 --- a/src/main/scala/beam/agentsim/infrastructure/DefaultRidehailFunctions.scala +++ b/src/main/scala/beam/agentsim/infrastructure/DefaultRidehailFunctions.scala @@ -20,11 +20,10 @@ import org.matsim.core.utils.collections.QuadTree import scala.collection.mutable -class DefaultRidehailFunctions[GEO: GeoLevel]( - geoQuadTree: QuadTree[GEO], - idToGeoMapping: scala.collection.Map[Id[GEO], GEO], - geoToTAZ: GEO => TAZ, - parkingZones: Map[Id[ParkingZoneId], ParkingZone[GEO]], +class DefaultRidehailFunctions( + geoQuadTree: QuadTree[TAZ], + idToGeoMapping: scala.collection.Map[Id[TAZ], TAZ], + parkingZones: Map[Id[ParkingZoneId], ParkingZone], parkingZoneIdToParkingZoneDepotData: mutable.Map[Id[ParkingZoneId], ParkingZoneDepotData], distanceFunction: (Coord, Coord) => Double, minSearchRadius: Double, @@ -36,10 +35,9 @@ class DefaultRidehailFunctions[GEO: GeoLevel]( fuelTypePrices: Map[FuelType, Double], rideHailConfig: BeamConfig.Beam.Agentsim.Agents.RideHail, skims: Skims -) extends InfrastructureFunctions[GEO]( +) extends InfrastructureFunctions( geoQuadTree, idToGeoMapping, - geoToTAZ, parkingZones, distanceFunction, minSearchRadius, @@ -65,7 +63,7 @@ class DefaultRidehailFunctions[GEO: GeoLevel]( * @return */ override protected def setupMNLParameters( - parkingAlternative: ParkingZoneSearch.ParkingAlternative[GEO], + parkingAlternative: ParkingZoneSearch.ParkingAlternative, inquiry: ParkingInquiry ): Map[ParkingMNL.Parameters, Double] = { val beamVehicle = inquiry.beamVehicle.get @@ -91,7 +89,7 @@ class DefaultRidehailFunctions[GEO: GeoLevel]( .refuelingSessionDurationAndEnergyInJoulesForStall( Some( ParkingStall - .fromParkingAlternative(geoToTAZ(parkingAlternative.geo).tazId, parkingAlternative) + .fromParkingAlternative(parkingAlternative.geo.tazId, parkingAlternative) ), None, None, @@ -114,7 +112,7 @@ class DefaultRidehailFunctions[GEO: GeoLevel]( * @return */ override protected def setupSearchFilterPredicates( - zone: ParkingZone[GEO], + zone: ParkingZone, inquiry: ParkingInquiry ): Boolean = { val beamVehicle = inquiry.beamVehicle.get @@ -123,12 +121,12 @@ class DefaultRidehailFunctions[GEO: GeoLevel]( /** * Generic method that specifies the behavior when MNL returns a ParkingZoneSearchResult - * @param parkingZoneSearchResult ParkingZoneSearchResult[GEO] + * @param parkingZoneSearchResult ParkingZoneSearchResult */ override protected def processParkingZoneSearchResult( inquiry: ParkingInquiry, - parkingZoneSearchResult: Option[ParkingZoneSearchResult[GEO]] - ): Option[ParkingZoneSearchResult[GEO]] = { + parkingZoneSearchResult: Option[ParkingZoneSearchResult] + ): Option[ParkingZoneSearchResult] = { parkingZoneSearchResult match { case Some( result @ ParkingZoneSearch.ParkingZoneSearchResult( @@ -153,21 +151,20 @@ class DefaultRidehailFunctions[GEO: GeoLevel]( } /** - * sample location of a parking stall with a GEO area + * sample location of a parking stall with a TAZ area * * @param inquiry ParkingInquiry - * @param parkingZone ParkingZone[GEO] - * @param geoArea GEO + * @param parkingZone ParkingZone + * @param taz TAZ * @return */ override protected def sampleParkingStallLocation( inquiry: ParkingInquiry, - parkingZone: ParkingZone[GEO], - geoArea: GEO, + parkingZone: ParkingZone, + taz: TAZ, inClosestZone: Boolean = true ): Coord = { - import GeoLevel.ops._ - geoArea.centroidLocation + taz.coord } /** @@ -180,7 +177,7 @@ class DefaultRidehailFunctions[GEO: GeoLevel]( * @return */ def secondsToServiceQueueAndChargingVehicles( - parkingZone: ParkingZone[GEO], + parkingZone: ParkingZone, tick: Int ): Int = { val parkingZoneDepotData = parkingZoneIdToParkingZoneDepotData(parkingZone.parkingZoneId) @@ -213,7 +210,7 @@ class DefaultRidehailFunctions[GEO: GeoLevel]( result } - def hasHighSocAndZoneIsDCFast(beamVehicle: BeamVehicle, parkingZone: ParkingZone[GEO]): Boolean = { + def hasHighSocAndZoneIsDCFast(beamVehicle: BeamVehicle, parkingZone: ParkingZone): Boolean = { val soc = beamVehicle.getStateOfCharge soc >= 0.8 && parkingZone.chargingPointType.exists(_.asInstanceOf[CustomChargingPoint].installedCapacity > 20.0) } @@ -225,10 +222,12 @@ class DefaultRidehailFunctions[GEO: GeoLevel]( * @return Parking zone location in UTM. */ def getParkingZoneLocationUtm(parkingZoneId: Id[ParkingZoneId]): Coord = { - val geoId = parkingZones(parkingZoneId).geoId - val geo = idToGeoMapping(geoId) - import GeoLevel.ops._ - geo.centroidLocation + val parkingZone = parkingZones(parkingZoneId) + parkingZone.link.fold { + idToGeoMapping(parkingZone.tazId).coord + } { + _.getCoord + } } } diff --git a/src/main/scala/beam/agentsim/infrastructure/HierarchicalParkingManager.scala b/src/main/scala/beam/agentsim/infrastructure/HierarchicalParkingManager.scala index 90085ea94f7..55137a47030 100644 --- a/src/main/scala/beam/agentsim/infrastructure/HierarchicalParkingManager.scala +++ b/src/main/scala/beam/agentsim/infrastructure/HierarchicalParkingManager.scala @@ -6,14 +6,15 @@ import beam.agentsim.agents.vehicles.VehicleManager.ReservedFor import beam.agentsim.infrastructure.HierarchicalParkingManager._ import beam.agentsim.infrastructure.charging.ChargingPointType import beam.agentsim.infrastructure.parking.ParkingZone.UbiqiutousParkingAvailability -import beam.agentsim.infrastructure.parking.ParkingZoneSearch.ZoneSearchTree import beam.agentsim.infrastructure.parking._ import beam.agentsim.infrastructure.taz.{TAZ, TAZTreeMap} import beam.router.BeamRouter.Location +import beam.sim.common.GeoUtils import beam.sim.config.BeamConfig +import beam.utils.matsim_conversion.ShapeUtils +import beam.utils.matsim_conversion.ShapeUtils.HasCoord import beam.utils.metrics.SimpleCounter import com.vividsolutions.jts.geom.Envelope -import org.matsim.api.core.v01.network.Link import org.matsim.api.core.v01.{Coord, Id} import org.matsim.core.utils.collections.QuadTree @@ -28,9 +29,8 @@ import scala.util.Random * @author Dmitry Openkov */ class HierarchicalParkingManager( - parkingZones: Map[Id[ParkingZoneId], ParkingZone[Link]], + parkingZones: Map[Id[ParkingZoneId], ParkingZone], tazMap: TAZTreeMap, - linkToTAZMapping: Map[Link, TAZ], distanceFunction: (Coord, Coord) => Double, minSearchRadius: Double, maxSearchRadius: Double, @@ -38,57 +38,43 @@ class HierarchicalParkingManager( seed: Int, mnlParkingConfig: BeamConfig.Beam.Agentsim.Agents.Parking.MulitnomialLogit, checkThatNumberOfStallsMatch: Boolean = false -) extends ParkingNetwork[Link](parkingZones) { - - /** - * Contains quad tree of links for each TAZ - */ - protected val tazLinks: Map[Id[TAZ], QuadTree[Link]] = createTazLinkQuadTreeMapping(linkToTAZMapping) +) extends ParkingNetwork(parkingZones) { protected val (tazParkingZones, linkZoneToTazZoneMap) = convertToTazParkingZones( - parkingZones, - linkToTAZMapping.map { case (link, taz) => - link.getId -> taz.tazId - } + parkingZones ) - protected val tazZoneSearchTree: ZoneSearchTree[TAZ] = - ParkingZoneFileUtils.createZoneSearchTree(tazParkingZones.values.toSeq) - - //HierarchicalParkingManager cannot provide search functions for its basic GEO unit - //it uses tazSearchFunctions to do the first level parking search - override protected val searchFunctions: Option[InfrastructureFunctions[Link]] = None - - private val tazSearchFunctions = new ParkingFunctions[TAZ]( - tazMap.tazQuadTree, - tazMap.idToTAZMapping, - identity[TAZ], - tazParkingZones, - distanceFunction, - minSearchRadius, - maxSearchRadius, - 0.0, - 0.0, - 1.0, - 1, - boundingBox, - seed, - mnlParkingConfig + override protected val searchFunctions: Option[InfrastructureFunctions] = Some( + new ParkingFunctions( + tazMap.tazQuadTree, + tazMap.idToTAZMapping, + tazParkingZones, + distanceFunction, + minSearchRadius, + maxSearchRadius, + 0.0, + 0.0, + 1.0, + 1, + boundingBox, + seed, + mnlParkingConfig + ) ) - val DefaultParkingZone: ParkingZone[Link] = + val DefaultParkingZone: ParkingZone = ParkingZone.defaultInit( - LinkLevelOperations.DefaultLinkId, + TAZ.DefaultTAZId, ParkingType.Public, UbiqiutousParkingAvailability ) /** - * each link is mapped to a Map: parking zone description -> list of parking zones with these params + * For each TAZ it contains a Map: ParkingZoneDescription -> ParkingZoneTreeMap */ - protected val linkZoneSearchMap: Map[Id[Link], Map[ParkingZoneDescription, IndexedSeq[ParkingZone[Link]]]] = - createLinkZoneSearchMap(parkingZones) + protected val tazSearchMap: Map[Id[TAZ], Map[ParkingZoneDescription, QuadTree[ParkingZone]]] = + createDescriptionToZonesMapForEachTaz(parkingZones, tazMap.idToTAZMapping) if (checkThatNumberOfStallsMatch) { val wrongTaz = wrongNumStallTazCollection() @@ -111,22 +97,26 @@ class HierarchicalParkingManager( //searchForParkingStall always returns a ParkingZoneSearchResult. It may contain either a real parkingStall // (success) or emergency parking stall (not found an appropriate one) val Some(ParkingZoneSearch.ParkingZoneSearchResult(tazParkingStall, tazParkingZone, _, _, _)) = - tazSearchFunctions.searchForParkingStall(inquiry) - - val (parkingStall: ParkingStall, parkingZone: ParkingZone[Link]) = - tazLinks.get(tazParkingZone.geoId) match { - case Some(linkQuadTree) => - findAppropriateLinkParkingStallWithinTaz(inquiry, tazParkingZone, linkQuadTree, tazParkingStall) - case None => //no corresponding links, this means it's a special zone - tazParkingStall.geoId match { - case TAZ.DefaultTAZId => - tazParkingStall.copy(geoId = LinkLevelOperations.DefaultLinkId) -> DefaultParkingZone - case TAZ.EmergencyTAZId => - tazParkingStall.copy(geoId = LinkLevelOperations.EmergencyLinkId) -> DefaultParkingZone - case _ => - logger.warn("Cannot find TAZ with id {}", tazParkingZone.geoId) - lastResortStallAndZone(inquiry.destinationUtm.loc) - } + searchFunctions.get.searchForParkingStall(inquiry) + + val (parkingStall: ParkingStall, parkingZone: ParkingZone) = + if (TAZ.isSpecialTazId(tazParkingStall.tazId)) tazParkingStall -> DefaultParkingZone + else { + val descriptionToZone = tazSearchMap(tazParkingZone.tazId) + findAppropriateLinkParkingZoneWithinTaz(tazParkingZone, descriptionToZone, inquiry.destinationUtm.loc) match { + case Some(zone) => + val linkParkingStall = tazParkingStall.copy( + parkingZoneId = zone.parkingZoneId, + locationUTM = zone.link.fold(tazParkingStall.locationUTM)(_.getCoord) + ) + linkParkingStall -> zone + case None => + logger.error( + "Cannot find link parking parking zone for taz zone {}. Parallel changing of stallsAvailable?", + tazParkingZone + ) + lastResortStallAndZone(inquiry.destinationUtm.loc) + } } // reserveStall is false when agent is only seeking pricing information @@ -138,57 +128,37 @@ class HierarchicalParkingManager( ) ParkingZone.claimStall(parkingZone) - tazSearchFunctions.claimStall(tazParkingZone) + searchFunctions.get.claimStall(tazParkingZone) } Some(ParkingInquiryResponse(parkingStall, inquiry.requestId, inquiry.triggerId)) } - private def findAppropriateLinkParkingStallWithinTaz( - inquiry: ParkingInquiry, - tazParkingZone: ParkingZone[TAZ], - linkQuadTree: QuadTree[Link], - tazParkingStall: ParkingStall - ): (ParkingStall, ParkingZone[Link]) = { + def findStartingPoint(taz: TAZ, destination: Coord): Coord = { + if (GeoUtils.isPointWithinCircle(taz.coord, taz.areaInSquareMeters / Math.PI, destination)) + destination + else GeoUtils.segmentCircleIntersection(taz.coord, Math.sqrt(taz.areaInSquareMeters / Math.PI), destination) + } + + private def findAppropriateLinkParkingZoneWithinTaz( + tazParkingZone: ParkingZone, + descriptionToZone: Map[ParkingZoneDescription, QuadTree[ParkingZone]], + destination: Coord + ): Option[ParkingZone] = { val foundZoneDescription = ParkingZoneDescription.describeParkingZone(tazParkingZone) - val startingPoint = - linkQuadTree.getClosest(inquiry.destinationUtm.loc.getX, inquiry.destinationUtm.loc.getY).getCoord + val treeMap: QuadTree[ParkingZone] = descriptionToZone(foundZoneDescription) + val taz = tazMap.idToTAZMapping(tazParkingZone.tazId) + + val startingPoint: Coord = findStartingPoint(taz, destination) TAZTreeMap.ringSearch( - linkQuadTree, + treeMap, startingPoint, - minSearchRadius / 4, - maxSearchRadius * 5, + 100, + 1000000, radiusMultiplication = 1.5 - ) { link => - for { - linkZones <- linkZoneSearchMap.get(link.getId) - zoneList <- linkZones.get(foundZoneDescription) - zone <- zoneList.find(_.stallsAvailable > 0) - } yield { - (tazParkingStall.copy(zone.geoId, parkingZoneId = zone.parkingZoneId, locationUTM = link.getCoord), zone) - } - } match { - case Some(foundResult) => foundResult - case None => //Cannot find required links within the TAZ, this means the links is too far from the starting point - logger.warn( - "Cannot find link parking stall for taz id {}, foundZoneDescription = {}, you could increase maxSearchRadius", - tazParkingZone.geoId, - foundZoneDescription - ) - import scala.collection.JavaConverters._ - val appropriateLinkZones = for { - link <- linkQuadTree.values().asScala.toList - linkZones <- linkZoneSearchMap.get(link.getId) - zoneList <- linkZones.get(foundZoneDescription) - zone <- zoneList.find(_.stallsAvailable > 0) - } yield { - zone -> link - } - logger.warn("Link zones {}", appropriateLinkZones) - val maybeAppropriateResult = appropriateLinkZones.headOption.map { case (zone, link) => - (tazParkingStall.copy(zone.geoId, parkingZoneId = zone.parkingZoneId, locationUTM = link.getCoord), zone) - } - maybeAppropriateResult.getOrElse(lastResortStallAndZone(inquiry.destinationUtm.loc)) + ) { parkingZone => + if (parkingZone.stallsAvailable > 0) Some(parkingZone) + else None } } @@ -210,7 +180,7 @@ class HierarchicalParkingManager( val tazZoneId = linkZoneToTazZoneMap(parkingZoneId) val tazZone = tazParkingZones(tazZoneId) ParkingZone.releaseStall(linkZone) - tazSearchFunctions.releaseStall(tazZone) + searchFunctions.get.releaseStall(tazZone) } } @@ -221,25 +191,17 @@ class HierarchicalParkingManager( private def wrongNumStallTazCollection(): Iterable[Id[TAZ]] = { tazMap.getTAZs .flatMap { taz => - val linkStalls = tazLinks - .get(taz.tazId) - .map { linkTree => - import scala.collection.JavaConverters._ - val links = linkTree.values().asScala - links.flatMap { link => - for { - map <- linkZoneSearchMap.get(link.getId).toIterable - zoneList <- map.values - zone <- zoneList - } yield zone.stallsAvailable.toLong - }.sum - } - .getOrElse(0L) + val linkStalls = (for { + descriptionsToQuadTrees <- tazSearchMap.get(taz.tazId) + totalStalls = descriptionsToQuadTrees.values + .map(_.values().stream().mapToLong(_.stallsAvailable).sum) + .sum + } yield totalStalls).getOrElse(0L) + val tazStalls = (for { - map <- tazZoneSearchTree.get(taz.tazId).toIterable - zoneIds <- map.values - zoneId <- zoneIds - } yield tazParkingZones(zoneId).stallsAvailable.toLong).sum + zoneCollection <- searchFunctions.get.zoneCollections.get(taz.tazId) + totalStalls = zoneCollection.parkingZones.map(_.stallsAvailable.toLong).sum + } yield totalStalls).getOrElse(0) if (tazStalls != linkStalls) Some(taz.tazId) else None } } @@ -251,12 +213,7 @@ class HierarchicalParkingManager( location.getY + 2000, location.getY - 2000 ) - val newStall = ParkingStall.lastResortStall( - boxAroundRequest, - new Random(seed), - tazId = TAZ.EmergencyTAZId, - geoId = LinkLevelOperations.EmergencyLinkId - ) + val newStall = ParkingStall.lastResortStall(boxAroundRequest, new Random(seed)) newStall -> DefaultParkingZone } } @@ -280,7 +237,7 @@ object HierarchicalParkingManager { object ParkingZoneDescription { - def describeParkingZone(zone: ParkingZone[_]): ParkingZoneDescription = { + def describeParkingZone(zone: ParkingZone): ParkingZoneDescription = { new ParkingZoneDescription( zone.parkingType, zone.reservedFor, @@ -292,9 +249,8 @@ object HierarchicalParkingManager { } def apply( - parkingZones: Map[Id[ParkingZoneId], ParkingZone[Link]], + parkingZones: Map[Id[ParkingZoneId], ParkingZone], tazMap: TAZTreeMap, - linkToTAZMapping: Map[Link, TAZ], distanceFunction: (Coord, Coord) => Double, minSearchRadius: Double, maxSearchRadius: Double, @@ -302,11 +258,10 @@ object HierarchicalParkingManager { seed: Int, mnlParkingConfig: BeamConfig.Beam.Agentsim.Agents.Parking.MulitnomialLogit, checkThatNumberOfStallsMatch: Boolean = false - ): ParkingNetwork[Link] = { + ): ParkingNetwork = { new HierarchicalParkingManager( parkingZones, tazMap, - linkToTAZMapping, distanceFunction, minSearchRadius, maxSearchRadius, @@ -318,9 +273,8 @@ object HierarchicalParkingManager { } def init( - parkingZones: Map[Id[ParkingZoneId], ParkingZone[Link]], + parkingZones: Map[Id[ParkingZoneId], ParkingZone], tazMap: TAZTreeMap, - linkToTAZMapping: Map[Link, TAZ], distanceFunction: (Coord, Coord) => Double, minSearchRadius: Double, maxSearchRadius: Double, @@ -328,11 +282,10 @@ object HierarchicalParkingManager { seed: Int, mnlParkingConfig: BeamConfig.Beam.Agentsim.Agents.Parking.MulitnomialLogit, checkThatNumberOfStallsMatch: Boolean = false - ): ParkingNetwork[Link] = + ): ParkingNetwork = HierarchicalParkingManager( parkingZones, tazMap, - linkToTAZMapping, distanceFunction, minSearchRadius, maxSearchRadius, @@ -345,14 +298,12 @@ object HierarchicalParkingManager { /** * Makes TAZ level parking data from the link level parking data * @param parkingZones link level parking zones - * @param linkToTAZMapping link to TAZ map * @return taz parking zones, link zone id -> taz zone id map */ private[infrastructure] def convertToTazParkingZones( - parkingZones: Map[Id[ParkingZoneId], ParkingZone[Link]], - linkToTAZMapping: Map[Id[Link], Id[TAZ]] - ): (Map[Id[ParkingZoneId], ParkingZone[TAZ]], Map[Id[ParkingZoneId], Id[ParkingZoneId]]) = { - val tazZonesMap = parkingZones.values.groupBy(zone => linkToTAZMapping(zone.geoId)) + parkingZones: Map[Id[ParkingZoneId], ParkingZone] + ): (Map[Id[ParkingZoneId], ParkingZone], Map[Id[ParkingZoneId], Id[ParkingZoneId]]) = { + val tazZonesMap = parkingZones.values.groupBy(_.tazId) // list of parking zone description including TAZ and link zones val tazZoneDescriptions = tazZonesMap.flatMap { case (tazId, currentTazParkingZones) => @@ -364,7 +315,7 @@ object HierarchicalParkingManager { //generate taz parking zones val tazZones = tazZoneDescriptions.zipWithIndex.map { case ((tazId, description, linkZones), id) => val numStalls = Math.min(linkZones.map(_.maxStalls.toLong).sum, Int.MaxValue).toInt - val parkingZone = ParkingZone.init[TAZ]( + val parkingZone = ParkingZone.init( Some(Id.create(id, classOf[ParkingZoneId])), geoId = tazId, parkingType = description.parkingType, @@ -384,26 +335,21 @@ object HierarchicalParkingManager { (tazZones.toMap, linkZoneToTazZoneMap.toMap) } - private def createLinkZoneSearchMap( - parkingZones: Map[Id[ParkingZoneId], ParkingZone[Link]] - ): Map[Id[Link], Map[ParkingZoneDescription, IndexedSeq[ParkingZone[Link]]]] = { - parkingZones.foldLeft(Map.empty: Map[Id[Link], Map[ParkingZoneDescription, IndexedSeq[ParkingZone[Link]]]]) { - case (accumulator, (_, zone)) => - val zoneDescription = ParkingZoneDescription.describeParkingZone(zone) - val parking = accumulator.getOrElse(zone.geoId, Map()) - val zoneList = parking.getOrElse(zoneDescription, IndexedSeq.empty) - accumulator.updated(zone.geoId, parking.updated(zoneDescription, zoneList :+ zone)) - } - } - - def createTazLinkQuadTreeMapping(linkToTAZMapping: Map[Link, TAZ]): Map[Id[TAZ], QuadTree[Link]] = { - val tazToLinks = invertMap(linkToTAZMapping) - tazToLinks.map { case (taz, links) => - taz.tazId -> LinkLevelOperations.getLinkTreeMap(links.toSeq) - } + private def createDescriptionToZonesMapForEachTaz( + parkingZones: Map[Id[ParkingZoneId], ParkingZone], + idToTazMapping: collection.Map[Id[TAZ], TAZ] + ): Map[Id[TAZ], Map[ParkingZoneDescription, QuadTree[ParkingZone]]] = { + val zoneLists = + parkingZones.values.foldLeft(Map.empty: Map[Id[TAZ], Map[ParkingZoneDescription, IndexedSeq[ParkingZone]]]) { + case (accumulator, zone) => + val zoneDescription = ParkingZoneDescription.describeParkingZone(zone) + val tazMap = accumulator.getOrElse(zone.tazId, Map.empty) + val zoneList = tazMap.getOrElse(zoneDescription, IndexedSeq.empty) + accumulator.updated(zone.tazId, tazMap.updated(zoneDescription, zoneList :+ zone)) + } + implicit val zoneHasCoord: HasCoord[ParkingZone] = + (zone: ParkingZone) => zone.link.fold(idToTazMapping(zone.tazId).coord)(_.getCoord) + zoneLists.mapValues(_.mapValues(zoneList => ShapeUtils.quadTree(zoneList))) } - private def invertMap(linkToTAZMapping: Map[Link, TAZ]): Map[TAZ, Set[Link]] = { - linkToTAZMapping.groupBy(_._2).mapValues(_.keys.toSet) - } } diff --git a/src/main/scala/beam/agentsim/infrastructure/InfrastructureFunctions.scala b/src/main/scala/beam/agentsim/infrastructure/InfrastructureFunctions.scala index 83401371eb4..74d1843efd4 100644 --- a/src/main/scala/beam/agentsim/infrastructure/InfrastructureFunctions.scala +++ b/src/main/scala/beam/agentsim/infrastructure/InfrastructureFunctions.scala @@ -20,11 +20,10 @@ import org.matsim.core.utils.collections.QuadTree import scala.util.Random -abstract class InfrastructureFunctions[GEO: GeoLevel]( - geoQuadTree: QuadTree[GEO], - idToGeoMapping: scala.collection.Map[Id[GEO], GEO], - geoToTAZ: GEO => TAZ, - parkingZones: Map[Id[ParkingZoneId], ParkingZone[GEO]], +abstract class InfrastructureFunctions( + geoQuadTree: QuadTree[TAZ], + idToGeoMapping: scala.collection.Map[Id[TAZ], TAZ], + parkingZones: Map[Id[ParkingZoneId], ParkingZone], distanceFunction: (Coord, Coord) => Double, minSearchRadius: Double, maxSearchRadius: Double, @@ -36,7 +35,7 @@ abstract class InfrastructureFunctions[GEO: GeoLevel]( seed: Int ) extends StrictLogging { - protected val zoneCollections: Map[Id[GEO], ParkingZoneCollection[GEO]] = + val zoneCollections: Map[Id[TAZ], ParkingZoneCollection] = ParkingZoneSearch.createZoneCollections(parkingZones.values.toSeq) protected val mnlMultiplierParameters: Map[ParkingMNL.Parameters, UtilityFunctionOperation] @@ -48,7 +47,7 @@ abstract class InfrastructureFunctions[GEO: GeoLevel]( * @return */ protected def setupMNLParameters( - parkingAlternative: ParkingAlternative[GEO], + parkingAlternative: ParkingAlternative, inquiry: ParkingInquiry ): Map[ParkingMNL.Parameters, Double] @@ -58,28 +57,28 @@ abstract class InfrastructureFunctions[GEO: GeoLevel]( * @param inquiry ParkingInquiry * @return */ - protected def setupSearchFilterPredicates(zone: ParkingZone[GEO], inquiry: ParkingInquiry): Boolean + protected def setupSearchFilterPredicates(zone: ParkingZone, inquiry: ParkingInquiry): Boolean /** * Generic method that specifies the behavior when MNL returns a ParkingZoneSearchResult - * @param parkingZoneSearchResult ParkingZoneSearchResult[GEO] + * @param parkingZoneSearchResult ParkingZoneSearchResult */ protected def processParkingZoneSearchResult( inquiry: ParkingInquiry, - parkingZoneSearchResult: Option[ParkingZoneSearchResult[GEO]] - ): Option[ParkingZoneSearchResult[GEO]] + parkingZoneSearchResult: Option[ParkingZoneSearchResult] + ): Option[ParkingZoneSearchResult] /** * sample location of a parking stall * @param inquiry ParkingInquiry - * @param parkingZone ParkingZone[GEO] - * @param geoArea GEO + * @param parkingZone ParkingZone + * @param taz TAZ * @return */ protected def sampleParkingStallLocation( inquiry: ParkingInquiry, - parkingZone: ParkingZone[GEO], - geoArea: GEO, + parkingZone: ParkingZone, + taz: TAZ, inClosestZone: Boolean = false ): Coord @@ -87,9 +86,9 @@ abstract class InfrastructureFunctions[GEO: GeoLevel]( import InfrastructureFunctions._ - val DefaultParkingZone: ParkingZone[GEO] = + val DefaultParkingZone: ParkingZone = ParkingZone.defaultInit( - GeoLevel[GEO].defaultGeoId, + TAZ.DefaultTAZId, ParkingType.Public, UbiqiutousParkingAvailability ) @@ -106,7 +105,7 @@ abstract class InfrastructureFunctions[GEO: GeoLevel]( minNumberOfSameTypeZones ) - def searchForParkingStall(inquiry: ParkingInquiry): Option[ParkingZoneSearch.ParkingZoneSearchResult[GEO]] = { + def searchForParkingStall(inquiry: ParkingInquiry): Option[ParkingZoneSearch.ParkingZoneSearchResult] = { // --------------------------------------------------------------------------------------------- // a ParkingZoneSearch takes the following as parameters // @@ -121,7 +120,7 @@ abstract class InfrastructureFunctions[GEO: GeoLevel]( // based on this. // --------------------------------------------------------------------------------------------- - val parkingZoneSearchParams: ParkingZoneSearchParams[GEO] = + val parkingZoneSearchParams: ParkingZoneSearchParams = ParkingZoneSearchParams( inquiry.destinationUtm.loc, inquiry.parkingDuration, @@ -142,36 +141,36 @@ abstract class InfrastructureFunctions[GEO: GeoLevel]( ) val closestZoneId = closestZone match { - case Some(foundZone) => GeoLevel[GEO].getId(foundZone) - case _ => GeoLevel[GEO].emergencyGeoId + case Some(foundZone) => foundZone.tazId + case _ => TAZ.EmergencyTAZId } // filters out ParkingZones which do not apply to this agent // TODO: check for conflicts between variables here - is it always false? - val parkingZoneFilterFunction: ParkingZone[GEO] => Boolean = - (zone: ParkingZone[GEO]) => { + val parkingZoneFilterFunction: ParkingZone => Boolean = + (zone: ParkingZone) => { val searchFilterPredicates = setupSearchFilterPredicates(zone, inquiry) searchFilterPredicates } // generates a coordinate for an embodied ParkingStall from a ParkingZone - val parkingZoneLocSamplingFunction: ParkingZone[GEO] => Coord = - (zone: ParkingZone[GEO]) => { - idToGeoMapping.get(zone.geoId) match { + val parkingZoneLocSamplingFunction: ParkingZone => Coord = + (zone: ParkingZone) => { + idToGeoMapping.get(zone.tazId) match { case None => logger.error( - s"somehow have a ParkingZone with geoId ${zone.geoId} which is not found in the idToGeoMapping" + s"somehow have a ParkingZone with tazId ${zone.tazId} which is not found in the idToGeoMapping" ) new Coord() case Some(taz) => - val inClosestZone = closestZoneId == zone.geoId + val inClosestZone = closestZoneId == zone.tazId sampleParkingStallLocation(inquiry, zone, taz, inClosestZone) } } // adds multinomial logit parameters to a ParkingAlternative - val parkingZoneMNLParamsFunction: ParkingAlternative[GEO] => Map[ParkingMNL.Parameters, Double] = - (parkingAlternative: ParkingAlternative[GEO]) => { + val parkingZoneMNLParamsFunction: ParkingAlternative => Map[ParkingMNL.Parameters, Double] = + (parkingAlternative: ParkingAlternative) => { val params = setupMNLParameters(parkingAlternative, inquiry) if (inquiry.parkingActivityType == ParkingActivityType.Home) { logger.debug( @@ -195,8 +194,7 @@ abstract class InfrastructureFunctions[GEO: GeoLevel]( parkingZoneSearchParams, parkingZoneFilterFunction, parkingZoneLocSamplingFunction, - parkingZoneMNLParamsFunction, - geoToTAZ + parkingZoneMNLParamsFunction ) ) @@ -225,15 +223,15 @@ abstract class InfrastructureFunctions[GEO: GeoLevel]( result } - def claimStall(parkingZone: ParkingZone[GEO]): Boolean = { + def claimStall(parkingZone: ParkingZone): Boolean = { val result = ParkingZone.claimStall(parkingZone) - zoneCollections.get(parkingZone.geoId).foreach(_.claimZone(parkingZone)) + zoneCollections.get(parkingZone.tazId).foreach(_.claimZone(parkingZone)) result } - def releaseStall(parkingZone: ParkingZone[GEO]): Boolean = { + def releaseStall(parkingZone: ParkingZone): Boolean = { val result = ParkingZone.releaseStall(parkingZone) - zoneCollections.get(parkingZone.geoId).foreach(_.releaseZone(parkingZone)) + zoneCollections.get(parkingZone.tazId).foreach(_.releaseZone(parkingZone)) result } diff --git a/src/main/scala/beam/agentsim/infrastructure/InfrastructureUtils.scala b/src/main/scala/beam/agentsim/infrastructure/InfrastructureUtils.scala index e261ff6c806..74727fad8ea 100644 --- a/src/main/scala/beam/agentsim/infrastructure/InfrastructureUtils.scala +++ b/src/main/scala/beam/agentsim/infrastructure/InfrastructureUtils.scala @@ -13,7 +13,6 @@ import beam.sim.{BeamScenario, BeamServices} import com.typesafe.scalalogging.LazyLogging import com.vividsolutions.jts.geom.Envelope import org.matsim.api.core.v01.Id -import org.matsim.api.core.v01.network.Link import org.matsim.core.utils.collections.QuadTree import scala.collection.JavaConverters._ @@ -32,7 +31,7 @@ object InfrastructureUtils extends LazyLogging { def buildParkingAndChargingNetworks( beamServices: BeamServices, envelopeInUTM: Envelope - ): (ParkingNetwork[_], ChargingNetwork[_], RideHailDepotParkingManager[_]) = { + ): (ParkingNetwork, ChargingNetwork, RideHailDepotParkingManager) = { implicit val beamScenario: BeamScenario = beamServices.beamScenario implicit val geo: GeoUtils = beamServices.geo implicit val boundingBox: Envelope = envelopeInUTM @@ -81,7 +80,7 @@ object InfrastructureUtils extends LazyLogging { } // CHARGING STALLS ARE LOADED HERE - val allChargingStalls = loadStalls[TAZ]( + val allChargingStalls = loadStalls( mainChargingFile, vehicleManagersParkingFiles, beamScenario.tazTreeMap.tazQuadTree, @@ -114,68 +113,31 @@ object InfrastructureUtils extends LazyLogging { // PARKING STALLS ARE LOADED HERE logger.info(s"loading stalls...") - val parkingStalls = beamConfig.beam.agentsim.taz.parkingManager.level.toLowerCase match { - case "taz" => - loadParkingStalls( - loadStalls[TAZ]( - mainParkingFile, - vehicleManagersParkingFiles, - beamScenario.tazTreeMap.tazQuadTree, - parkingStallCountScalingFactor, - parkingCostScalingFactor, - beamScenario.beamConfig.matsim.modules.global.randomSeed, - beamScenario.beamConfig, - Some(beamServices) - ) - ) - case "link" => - loadParkingStalls( - loadStalls[Link]( - mainParkingFile, - vehicleManagersParkingFiles, - beamScenario.linkQuadTree, - parkingStallCountScalingFactor, - parkingCostScalingFactor, - beamScenario.beamConfig.matsim.modules.global.randomSeed, - beamScenario.beamConfig, - Some(beamServices) - ) - ) - case _ => - throw new IllegalArgumentException( - s"Unsupported parking level type ${parkingManagerCfg.level}, only TAZ | Link are supported" - ) - } + val parkingStalls = loadParkingStalls( + loadStalls( + mainParkingFile, + vehicleManagersParkingFiles, + beamScenario.tazTreeMap.tazQuadTree, + parkingStallCountScalingFactor, + parkingCostScalingFactor, + beamScenario.beamConfig.matsim.modules.global.randomSeed, + beamScenario.beamConfig, + Some(beamServices) + ) + ) logger.info(s"building parking networks...") val parkingNetwork = beamConfig.beam.agentsim.taz.parkingManager.method match { case "DEFAULT" => - beamConfig.beam.agentsim.taz.parkingManager.level.toLowerCase match { - case "taz" => - ZonalParkingManager.init( - parkingStalls.asInstanceOf[Map[Id[ParkingZoneId], ParkingZone[TAZ]]], - envelopeInUTM, - beamServices - ) - case "link" => - ZonalParkingManager.init( - parkingStalls.asInstanceOf[Map[Id[ParkingZoneId], ParkingZone[Link]]], - beamScenario.linkQuadTree, - beamScenario.linkIdMapping, - beamScenario.linkToTAZMapping, - envelopeInUTM, - beamServices - ) - case _ => - throw new IllegalArgumentException( - s"Unsupported parking level type ${parkingManagerCfg.level}, only TAZ | Link are supported" - ) - } + ZonalParkingManager.init( + parkingStalls, + envelopeInUTM, + beamServices + ) case "HIERARCHICAL" => HierarchicalParkingManager .init( - parkingStalls.asInstanceOf[Map[Id[ParkingZoneId], ParkingZone[Link]]], + parkingStalls, beamScenario.tazTreeMap, - beamScenario.linkToTAZMapping, geo.distUTMInMeters(_, _), beamConfig.beam.agentsim.agents.parking.minSearchRadius, beamConfig.beam.agentsim.agents.parking.maxSearchRadius, @@ -185,7 +147,7 @@ object InfrastructureUtils extends LazyLogging { ) case "PARALLEL" => ParallelParkingManager.init( - parkingStalls.asInstanceOf[Map[Id[ParkingZoneId], ParkingZone[TAZ]]], + parkingStalls, beamScenario.beamConfig, beamScenario.tazTreeMap, geo.distUTMInMeters, @@ -206,18 +168,18 @@ object InfrastructureUtils extends LazyLogging { * @param beamConfig beam config * @return */ - def loadStalls[GEO: GeoLevel]( + def loadStalls( parkingFilePath: String, depotFilePaths: IndexedSeq[(String, ReservedFor, Seq[ParkingType])], - geoQuadTree: QuadTree[GEO], + geoQuadTree: QuadTree[TAZ], parkingStallCountScalingFactor: Double, parkingCostScalingFactor: Double, seed: Long, beamConfig: BeamConfig, beamServicesMaybe: Option[BeamServices] - ): Map[Id[ParkingZoneId], ParkingZone[GEO]] = { + ): Map[Id[ParkingZoneId], ParkingZone] = { val random = new Random(seed) - val initialAccumulator: ParkingLoadingAccumulator[GEO] = if (parkingFilePath.isEmpty) { + val initialAccumulator: ParkingLoadingAccumulator = if (parkingFilePath.isEmpty) { ParkingZoneFileUtils.generateDefaultParkingAccumulatorFromGeoObjects( geoQuadTree.values().asScala, random, @@ -280,20 +242,20 @@ object InfrastructureUtils extends LazyLogging { } /** - * @param stalls Map[Id[ParkingZoneId], ParkingZone[GEO]] + * @param stalls Map[Id[ParkingZoneId], ParkingZone] * @return */ - def loadParkingStalls[GEO]( - stalls: Map[Id[ParkingZoneId], ParkingZone[GEO]] - ): Map[Id[ParkingZoneId], ParkingZone[GEO]] = stalls.filter(_._2.chargingPointType.isEmpty) + def loadParkingStalls( + stalls: Map[Id[ParkingZoneId], ParkingZone] + ): Map[Id[ParkingZoneId], ParkingZone] = stalls.filter(_._2.chargingPointType.isEmpty) /** * @param stalls list of parking zones * @return */ - def loadRideHailChargingStalls[GEO]( - stalls: Map[Id[ParkingZoneId], ParkingZone[GEO]] - ): Map[Id[VehicleManager], Map[Id[ParkingZoneId], ParkingZone[GEO]]] = { + def loadRideHailChargingStalls( + stalls: Map[Id[ParkingZoneId], ParkingZone] + ): Map[Id[VehicleManager], Map[Id[ParkingZoneId], ParkingZone]] = { import VehicleManager._ stalls .filter(x => x._2.chargingPointType.nonEmpty && x._2.reservedFor.managerType == TypeEnum.RideHail) @@ -304,9 +266,9 @@ object InfrastructureUtils extends LazyLogging { * @param stalls list of parking zones * @return */ - def loadChargingStalls[GEO]( - stalls: Map[Id[ParkingZoneId], ParkingZone[GEO]] - ): Map[Id[ParkingZoneId], ParkingZone[GEO]] = { + def loadChargingStalls( + stalls: Map[Id[ParkingZoneId], ParkingZone] + ): Map[Id[ParkingZoneId], ParkingZone] = { import VehicleManager._ stalls.filter(x => x._2.chargingPointType.nonEmpty && x._2.reservedFor.managerType != TypeEnum.RideHail) } diff --git a/src/main/scala/beam/agentsim/infrastructure/ParallelParkingManager.scala b/src/main/scala/beam/agentsim/infrastructure/ParallelParkingManager.scala index 24429be06ee..c27cbf02f0c 100644 --- a/src/main/scala/beam/agentsim/infrastructure/ParallelParkingManager.scala +++ b/src/main/scala/beam/agentsim/infrastructure/ParallelParkingManager.scala @@ -31,7 +31,7 @@ import scala.collection.mutable.ArrayBuffer * @author Dmitry Openkov */ class ParallelParkingManager( - parkingZones: Map[Id[ParkingZoneId], ParkingZone[TAZ]], + parkingZones: Map[Id[ParkingZoneId], ParkingZone], tazTreeMap: TAZTreeMap, clusters: Vector[ParkingCluster], distanceFunction: (Coord, Coord) => Double, @@ -42,9 +42,9 @@ class ParallelParkingManager( minNumberOfSameTypeZones: Int, seed: Int, mnlParkingConfig: BeamConfig.Beam.Agentsim.Agents.Parking.MulitnomialLogit -) extends ParkingNetwork[TAZ](parkingZones) { +) extends ParkingNetwork(parkingZones) { - override protected val searchFunctions: Option[InfrastructureFunctions[TAZ]] = None + override protected val searchFunctions: Option[InfrastructureFunctions] = None protected val workers: Vector[Worker] = clusters.zipWithIndex.map { case (cluster, _) => createWorker(cluster) @@ -65,11 +65,10 @@ class ParallelParkingManager( protected def createWorker(cluster: ParkingCluster): Worker = { val tazTreeMap = TAZTreeMap.fromSeq(cluster.tazes) - val parkingNetwork = ZonalParkingManager[TAZ]( + val parkingNetwork = ZonalParkingManager( parkingZones, tazTreeMap.tazQuadTree, tazTreeMap.idToTAZMapping, - identity[TAZ](_), distanceFunction, boundingBox, minSearchRadius, @@ -146,12 +145,12 @@ object ParallelParkingManager extends LazyLogging { * @return */ def init( - parkingZones: Map[Id[ParkingZoneId], ParkingZone[TAZ]], + parkingZones: Map[Id[ParkingZoneId], ParkingZone], beamConfig: BeamConfig, tazTreeMap: TAZTreeMap, distanceFunction: (Coord, Coord) => Double, boundingBox: Envelope - ): ParkingNetwork[TAZ] = { + ): ParkingNetwork = { val seed = beamConfig.matsim.modules.global.randomSeed val numClusters = Math.min(tazTreeMap.tazQuadTree.size(), beamConfig.beam.agentsim.taz.parkingManager.parallel.numberOfClusters) @@ -167,14 +166,14 @@ object ParallelParkingManager extends LazyLogging { } def init( - parkingZones: Map[Id[ParkingZoneId], ParkingZone[TAZ]], + parkingZones: Map[Id[ParkingZoneId], ParkingZone], beamConfig: BeamConfig, tazTreeMap: TAZTreeMap, distanceFunction: (Coord, Coord) => Double, boundingBox: Envelope, seed: Int, numClusters: Int - ): ParkingNetwork[TAZ] = { + ): ParkingNetwork = { val clusters: Vector[ParkingCluster] = createClusters(tazTreeMap, parkingZones, numClusters, seed.toLong) new ParallelParkingManager( @@ -199,11 +198,11 @@ object ParallelParkingManager extends LazyLogging { presentation: String ) - protected case class Worker(actor: ParkingNetwork[TAZ], cluster: ParkingCluster) + protected case class Worker(actor: ParkingNetwork, cluster: ParkingCluster) private[infrastructure] def createClusters( tazTreeMap: TAZTreeMap, - zones: Map[Id[ParkingZoneId], ParkingZone[TAZ]], + zones: Map[Id[ParkingZoneId], ParkingZone], numClusters: Int, seed: Long ): Vector[ParkingCluster] = { @@ -240,7 +239,7 @@ object ParallelParkingManager extends LazyLogging { val rel = db.getRelation(TypeUtil.DOUBLE_VECTOR_FIELD) val labels: Relation[String] = db.getRelation(TypeUtil.STRING) val coords: ArrayBuffer[Coordinate] = new ArrayBuffer(clu.size()) - val clusterZones: ArrayBuffer[ParkingZone[TAZ]] = new ArrayBuffer(clu.size()) + val clusterZones: ArrayBuffer[ParkingZone] = new ArrayBuffer(clu.size()) val empty: ArrayBuffer[TAZ] = new ArrayBuffer[TAZ]() val iter: DBIDIter = clu.getIDs.iter() while (iter.valid()) { @@ -266,7 +265,7 @@ object ParallelParkingManager extends LazyLogging { val ch = new ConvexHull(dCoords.toArray, geometryFactory).getConvexHull val convexHull = pgf.create(ch) val tazes = clusterZones - .map(_.geoId) + .map(_.tazId) .distinct .map(tazTreeMap.getTAZ(_).get) ++ empty val centroid = ch.getCentroid @@ -281,17 +280,17 @@ object ParallelParkingManager extends LazyLogging { private def createDatabase( tazTreeMap: TAZTreeMap, - zones: Map[Id[ParkingZoneId], ParkingZone[TAZ]] + zones: Map[Id[ParkingZoneId], ParkingZone] ): (Array[TAZ], StaticArrayDatabase) = { case class ZoneInfo(coord: Coord, label: String) val zoneInfos = { zones.flatMap { case (_, zone) => tazTreeMap - .getTAZ(zone.geoId) + .getTAZ(zone.tazId) .map(taz => ZoneInfo(taz.coord, zone.parkingZoneId.toString)) } } - val emptyTAZes = (tazTreeMap.getTAZs.toSet -- zones.flatMap(zone => tazTreeMap.getTAZ(zone._2.geoId)).toSet).toArray + val emptyTAZes = (tazTreeMap.getTAZs.toSet -- zones.flatMap(zone => tazTreeMap.getTAZ(zone._2.tazId)).toSet).toArray val virtualZones = emptyTAZes.zipWithIndex.map { case (taz, idx) => ZoneInfo(taz.coord, s"taz$idx") } diff --git a/src/main/scala/beam/agentsim/infrastructure/ParkingFunctions.scala b/src/main/scala/beam/agentsim/infrastructure/ParkingFunctions.scala index 7c25269f638..84f1b16a84f 100644 --- a/src/main/scala/beam/agentsim/infrastructure/ParkingFunctions.scala +++ b/src/main/scala/beam/agentsim/infrastructure/ParkingFunctions.scala @@ -14,11 +14,10 @@ import org.matsim.core.utils.collections.QuadTree import scala.util.Random -class ParkingFunctions[GEO: GeoLevel]( - geoQuadTree: QuadTree[GEO], - idToGeoMapping: scala.collection.Map[Id[GEO], GEO], - geoToTAZ: GEO => TAZ, - parkingZones: Map[Id[ParkingZoneId], ParkingZone[GEO]], +class ParkingFunctions( + geoQuadTree: QuadTree[TAZ], + idToGeoMapping: scala.collection.Map[Id[TAZ], TAZ], + parkingZones: Map[Id[ParkingZoneId], ParkingZone], distanceFunction: (Coord, Coord) => Double, minSearchRadius: Double, maxSearchRadius: Double, @@ -29,10 +28,9 @@ class ParkingFunctions[GEO: GeoLevel]( boundingBox: Envelope, seed: Int, mnlParkingConfig: BeamConfig.Beam.Agentsim.Agents.Parking.MulitnomialLogit -) extends InfrastructureFunctions[GEO]( +) extends InfrastructureFunctions( geoQuadTree, idToGeoMapping, - geoToTAZ, parkingZones, distanceFunction, minSearchRadius, @@ -71,7 +69,7 @@ class ParkingFunctions[GEO: GeoLevel]( * @return */ override protected def setupMNLParameters( - parkingAlternative: ParkingAlternative[GEO], + parkingAlternative: ParkingAlternative, inquiry: ParkingInquiry ): Map[ParkingMNL.Parameters, Double] = { val distance: Double = distanceFunction(inquiry.destinationUtm.loc, parkingAlternative.coord) @@ -138,7 +136,7 @@ class ParkingFunctions[GEO: GeoLevel]( * @return */ override protected def setupSearchFilterPredicates( - zone: ParkingZone[GEO], + zone: ParkingZone, inquiry: ParkingInquiry ): Boolean = { if (zone.chargingPointType.isDefined) @@ -150,18 +148,18 @@ class ParkingFunctions[GEO: GeoLevel]( /** * Generic method that specifies the behavior when MNL returns a ParkingZoneSearchResult - * @param parkingZoneSearchResult ParkingZoneSearchResult[GEO] + * @param parkingZoneSearchResult ParkingZoneSearchResult */ override protected def processParkingZoneSearchResult( inquiry: ParkingInquiry, - parkingZoneSearchResult: Option[ParkingZoneSearchResult[GEO]] - ): Option[ParkingZoneSearchResult[GEO]] = { + parkingZoneSearchResult: Option[ParkingZoneSearchResult] + ): Option[ParkingZoneSearchResult] = { val output = parkingZoneSearchResult match { case Some(result) => result case _ => inquiry.parkingActivityType match { case ParkingActivityType.Init | ParkingActivityType.Home => - val newStall = ParkingStall.defaultResidentialStall(inquiry.destinationUtm.loc, GeoLevel[GEO].defaultGeoId) + val newStall = ParkingStall.defaultResidentialStall(inquiry.destinationUtm.loc) ParkingZoneSearch.ParkingZoneSearchResult(newStall, DefaultParkingZone) case _ => // didn't find any stalls, so, as a last resort, create a very expensive stall @@ -171,12 +169,7 @@ class ParkingFunctions[GEO: GeoLevel]( inquiry.destinationUtm.loc.getY + 2000, inquiry.destinationUtm.loc.getY - 2000 ) - val newStall = ParkingStall.lastResortStall( - boxAroundRequest, - new Random(seed), - tazId = TAZ.EmergencyTAZId, - geoId = GeoLevel[GEO].emergencyGeoId - ) + val newStall = ParkingStall.lastResortStall(boxAroundRequest, new Random(seed)) ParkingZoneSearch.ParkingZoneSearchResult(newStall, DefaultParkingZone) } } @@ -184,16 +177,16 @@ class ParkingFunctions[GEO: GeoLevel]( } /** - * sample location of a parking stall with a GEO area + * sample location of a parking stall with a TAZ area * * @param inquiry ParkingInquiry - * @param parkingZone ParkingZone[GEO] - * @param geoArea GEO + * @param parkingZone ParkingZone + * @param taz TAZ */ override protected def sampleParkingStallLocation( inquiry: ParkingInquiry, - parkingZone: ParkingZone[GEO], - geoArea: GEO, + parkingZone: ParkingZone, + taz: TAZ, inClosestZone: Boolean = true ): Coord = { if (parkingZone.link.isDefined) @@ -201,10 +194,10 @@ class ParkingFunctions[GEO: GeoLevel]( else if (parkingZone.reservedFor.managerType == VehicleManager.TypeEnum.Household) inquiry.destinationUtm.loc else - GeoLevel[GEO].geoSampling( + ParkingStallSampling.availabilityAwareSampling( new Random(seed), inquiry.destinationUtm.loc, - geoArea, + taz, parkingZone.availability, inClosestZone ) @@ -218,7 +211,7 @@ class ParkingFunctions[GEO: GeoLevel]( * @return */ protected def canThisCarParkHere( - zone: ParkingZone[GEO], + zone: ParkingZone, inquiry: ParkingInquiry, preferredParkingTypes: Set[ParkingType] ): Boolean = { diff --git a/src/main/scala/beam/agentsim/infrastructure/ParkingManagerBenchmark.scala b/src/main/scala/beam/agentsim/infrastructure/ParkingManagerBenchmark.scala index 34cabfebd30..763b8e7429c 100644 --- a/src/main/scala/beam/agentsim/infrastructure/ParkingManagerBenchmark.scala +++ b/src/main/scala/beam/agentsim/infrastructure/ParkingManagerBenchmark.scala @@ -3,7 +3,6 @@ package beam.agentsim.infrastructure import akka.actor.ActorSystem import akka.util.Timeout import beam.agentsim.events.SpaceTime -import beam.agentsim.infrastructure.parking.ParkingZoneSearch.ZoneSearchTree import beam.agentsim.infrastructure.parking._ import beam.agentsim.infrastructure.taz.{TAZ, TAZTreeMap} import beam.sim.common.GeoUtils @@ -29,7 +28,7 @@ import scala.util.Random class ParkingManagerBenchmark( val possibleParkingLocations: Array[(Coord, String)], - val parkingNetwork: ParkingNetwork[_] + val parkingNetwork: ParkingNetwork )(implicit val actorSystem: ActorSystem, val ec: ExecutionContext @@ -63,14 +62,11 @@ object ParkingManagerBenchmark extends StrictLogging { // val pathToPlans: String = "https://beam-outputs.s3.us-east-2.amazonaws.com/parallel_parking_manager/0.plans.xml.gz" // val pathToTazParking: String = "production/sfbay/gemini/infrastructure/4a_output_2022_Apr_13_pubClust_withFees_aggregated.csv" - val pathToTazParking: String = "production/sfbay/gemini/infrastructure/init1-7_2022_Feb_03_wgs84_withFees_cleaned.csv" + val pathToTazParking: String = + "production/sfbay/gemini/infrastructure/gemini-base-scenario-3-charging-no-household-infra16.csv" // val pathToTazParking: String = // "https://beam-outputs.s3.us-east-2.amazonaws.com/parallel_parking_manager/taz-parking-unlimited-fast-limited-l2-150-baseline.csv.gz" - val pathToLinkParking: String = "production/sfbay/gemini/infrastructure/init1-7_2022_Feb_03_wgs84_withFees_link.csv" - // val pathToLinkParking: String = - // "https://beam-outputs.s3.us-east-2.amazonaws.com/parallel_parking_manager/link-parking-unlimited-fast-limited-l2-150-baseline.csv.gz" - val pathToTAZ: String = "production/sfbay/taz-centers.csv" // val pathToTAZ: String = "https://beam-outputs.s3.us-east-2.amazonaws.com/parallel_parking_manager/taz-centers.csv.gz" @@ -110,18 +106,18 @@ object ParkingManagerBenchmark extends StrictLogging { val seed: Int = 42 val nTimes: Int = 1 - val fractionToBench: Double = 0.1 + val fractionToBench: Double = 1.0 def main(args: Array[String]): Unit = { implicit val ec: ExecutionContext = scala.concurrent.ExecutionContext.Implicits.global - def loadZones[GEO: GeoLevel]( - quadTree: QuadTree[GEO], + def loadZones( + quadTree: QuadTree[TAZ], pathToParking: String, beamConfig: BeamConfig - ): (Map[Id[ParkingZoneId], ParkingZone[GEO]], ZoneSearchTree[GEO]) = { + ): Map[Id[ParkingZoneId], ParkingZone] = { logger.info("Start loading parking zones from {}", pathToParking) - val zones = InfrastructureUtils.loadStalls[GEO]( + val zones = InfrastructureUtils.loadStalls( pathToParking, IndexedSeq.empty, quadTree, @@ -131,11 +127,9 @@ object ParkingManagerBenchmark extends StrictLogging { beamConfig, None ) - val searchTree = ParkingZoneFileUtils.createZoneSearchTree(zones.values.toSeq) logger.info(s"Number of zones: ${zones.size}") logger.info(s"Number of parking stalls: ${zones.map(_._2.stallsAvailable.toLong).sum}") - logger.info(s"SearchTree size: ${searchTree.size}") - (zones, searchTree) + zones } try { @@ -163,43 +157,24 @@ object ParkingManagerBenchmark extends StrictLogging { } val allActivityLocations: Array[(Coord, String)] = activities.map(act => (act.getCoord, act.getType)).toArray - def createZonalParkingManager(isLink: Boolean): ParkingNetwork[_] = { - if (isLink) { - val linkQuadTree: QuadTree[Link] = LinkLevelOperations.getLinkTreeMap(network.getLinks.values().asScala.toSeq) - val linkIdMapping: collection.Map[Id[Link], Link] = LinkLevelOperations.getLinkIdMapping(network) - val linkToTAZMapping: Map[Link, TAZ] = LinkLevelOperations.getLinkToTazMapping(network, tazTreeMap) - val (zones, _) = loadZones(linkQuadTree, pathToLinkParking, beamConfig) - logger.info(s"linkQuadTree size = ${linkQuadTree.size()}") - val parkingNetwork = ZonalParkingManager[Link]( - zones, - linkQuadTree, - linkIdMapping, - linkToTAZMapping, - boundingBox, - beamConfig, - geoUtils.distUTMInMeters(_, _) - ) - parkingNetwork - } else { - val (zones, _) = loadZones(tazTreeMap.tazQuadTree, pathToTazParking, beamConfig) - val parkingNetwork = ZonalParkingManager[TAZ]( - zones, - tazTreeMap.tazQuadTree, - tazTreeMap.idToTAZMapping, - identity[TAZ](_), - boundingBox, - beamConfig, - geoUtils.distUTMInMeters(_, _) - ) - parkingNetwork - } + def createZonalParkingManager(isLink: Boolean): ParkingNetwork = { + val zones = loadZones(tazTreeMap.tazQuadTree, pathToTazParking, beamConfig) + val parkingNetwork = ZonalParkingManager( + zones, + tazTreeMap.tazQuadTree, + tazTreeMap.idToTAZMapping, + boundingBox, + beamConfig, + geoUtils.distUTMInMeters(_, _) + ) + parkingNetwork } def runBench(activityLocations: Array[(Coord, String)], managerType: String): List[ParkingInquiryResponse] = { // This is important! because `ParkingZone` is mutable class val parkingNetwork = managerType match { case "parallel" => - val (zones, _) = loadZones(tazTreeMap.tazQuadTree, pathToTazParking, beamConfig) + val zones = loadZones(tazTreeMap.tazQuadTree, pathToTazParking, beamConfig) val parkingNetwork = ParallelParkingManager.init( zones, @@ -214,36 +189,10 @@ object ParkingManagerBenchmark extends StrictLogging { case "zonal" => createZonalParkingManager(isLink = false) case "hierarchical" => - val linkQuadTree: QuadTree[Link] = - LinkLevelOperations.getLinkTreeMap(network.getLinks.values().asScala.toSeq) - val linkToTAZMapping: Map[Link, TAZ] = LinkLevelOperations.getLinkToTazMapping(network, tazTreeMap) - val (zones, _) = loadZones(linkQuadTree, pathToLinkParking, beamConfig) + val zones = loadZones(tazTreeMap.tazQuadTree, pathToTazParking, beamConfig) val parkingNetwork = HierarchicalParkingManager.init( zones, tazTreeMap, - linkToTAZMapping, - geoUtils.distUTMInMeters, - beamConfig.beam.agentsim.agents.parking.minSearchRadius, - beamConfig.beam.agentsim.agents.parking.maxSearchRadius, - boundingBox, - seed, - beamConfig.beam.agentsim.agents.parking.mulitnomialLogit, - checkThatNumberOfStallsMatch = true - ) - parkingNetwork - case "hierarchical-taz" => - val linkQuadTree: QuadTree[Link] = - LinkLevelOperations.getLinkTreeMap(network.getLinks.values().asScala.toSeq) - val linkToTAZMapping: Map[Link, TAZ] = LinkLevelOperations.getLinkToTazMapping(network, tazTreeMap) - val (tazZones: Map[Id[ParkingZoneId], ParkingZone[TAZ]], _) = - loadZones(tazTreeMap.tazQuadTree, pathToTazParking, beamConfig) - val linkParkingZones: Map[Id[ParkingZoneId], ParkingZone[Link]] = ParkingZoneFileUtils - .generateLinkParkingOutOfTazParking(tazZones, linkQuadTree, linkToTAZMapping, tazTreeMap) -// ParkingZoneFileUtils.toCsv(linkParkingZones, "production/sfbay/parking/init1-7_2022_Feb_03_wgs84_withFees_link.csv") - val parkingNetwork = HierarchicalParkingManager.init( - linkParkingZones, - tazTreeMap, - linkToTAZMapping, geoUtils.distUTMInMeters, beamConfig.beam.agentsim.agents.parking.minSearchRadius, beamConfig.beam.agentsim.agents.parking.maxSearchRadius, @@ -298,7 +247,7 @@ object ParkingManagerBenchmark extends StrictLogging { logger.info(zonalResult) logger.info("#####################################################################") - writeToCsv(responses, "./hir_parking.csv") + writeToCsv(responses, "./test_parking.csv") writeToCsv(zonalResponses, "./zonal_parking.csv") analyzeResult(responses.head.groupBy(_.stall.tazId), zonalResponses.head.groupBy(_.stall.tazId)) @@ -311,7 +260,7 @@ object ParkingManagerBenchmark extends StrictLogging { new CsvWriter(path, "geo_id", "x", "y") .writeAllAndClose( zonalResponses - .flatMap(_.map(resp => List(resp.stall.geoId, resp.stall.locationUTM.getX, resp.stall.locationUTM.getY))) + .flatMap(_.map(resp => List(resp.stall.tazId, resp.stall.locationUTM.getX, resp.stall.locationUTM.getY))) ) } diff --git a/src/main/scala/beam/agentsim/infrastructure/ParkingNetworkManager.scala b/src/main/scala/beam/agentsim/infrastructure/ParkingNetworkManager.scala index b42277ce20a..ad3bcc1adb4 100644 --- a/src/main/scala/beam/agentsim/infrastructure/ParkingNetworkManager.scala +++ b/src/main/scala/beam/agentsim/infrastructure/ParkingNetworkManager.scala @@ -12,7 +12,7 @@ import com.typesafe.scalalogging.LazyLogging import scala.concurrent.duration._ -class ParkingNetworkManager(beamServices: BeamServices, parkingNetworkMap: ParkingNetwork[_]) +class ParkingNetworkManager(beamServices: BeamServices, parkingNetworkMap: ParkingNetwork) extends beam.utils.CriticalActor with LoggingMessageActor with ActorLogging { @@ -43,7 +43,7 @@ class ParkingNetworkManager(beamServices: BeamServices, parkingNetworkMap: Parki object ParkingNetworkManager extends LazyLogging { - def props(services: BeamServices, parkingNetworkMap: ParkingNetwork[_]): Props = { + def props(services: BeamServices, parkingNetworkMap: ParkingNetwork): Props = { Props(new ParkingNetworkManager(services, parkingNetworkMap)) } } diff --git a/src/main/scala/beam/agentsim/infrastructure/ParkingStall.scala b/src/main/scala/beam/agentsim/infrastructure/ParkingStall.scala index 107d4e7103d..415443fb7bc 100755 --- a/src/main/scala/beam/agentsim/infrastructure/ParkingStall.scala +++ b/src/main/scala/beam/agentsim/infrastructure/ParkingStall.scala @@ -13,7 +13,6 @@ import org.matsim.api.core.v01.{Coord, Id} import scala.util.Random case class ParkingStall( - geoId: Id[_], tazId: Id[TAZ], parkingZoneId: Id[ParkingZoneId], locationUTM: Location, @@ -28,14 +27,13 @@ object ParkingStall { val CostOfEmergencyStallInDollars: Double = 50.0 - def init[T]( - parkingZone: ParkingZone[T], + def init( + parkingZone: ParkingZone, tazId: Id[TAZ], location: Location, costInDollars: Double ): ParkingStall = { ParkingStall( - parkingZone.geoId, tazId, parkingZone.parkingZoneId, location, @@ -53,7 +51,6 @@ object ParkingStall { * @return a new parking stall with the default Id[Taz] and parkingZoneId */ def defaultStall(coord: Coord): ParkingStall = ParkingStall( - geoId = TAZ.DefaultTAZId, tazId = TAZ.DefaultTAZId, parkingZoneId = ParkingZone.DefaultParkingZoneId, locationUTM = coord, @@ -75,16 +72,13 @@ object ParkingStall { def lastResortStall( boundingBox: Envelope, random: Random = Random, - costInDollars: Double = CostOfEmergencyStallInDollars, - tazId: Id[TAZ] = TAZ.EmergencyTAZId, - geoId: Id[_] + costInDollars: Double = CostOfEmergencyStallInDollars ): ParkingStall = { val x = random.nextDouble() * (boundingBox.getMaxX - boundingBox.getMinX) + boundingBox.getMinX val y = random.nextDouble() * (boundingBox.getMaxY - boundingBox.getMinY) + boundingBox.getMinY ParkingStall( - geoId = geoId, - tazId = tazId, + tazId = TAZ.EmergencyTAZId, parkingZoneId = ParkingZone.DefaultParkingZoneId, locationUTM = new Coord(x, y), costInDollars = costInDollars, @@ -105,11 +99,7 @@ object ParkingStall { * * @return a stall that is free and located at the person's home. */ - def defaultResidentialStall( - locationUTM: Location, - defaultGeoId: Id[_] - ): ParkingStall = ParkingStall( - geoId = defaultGeoId, + def defaultResidentialStall(locationUTM: Location): ParkingStall = ParkingStall( tazId = TAZ.DefaultTAZId, parkingZoneId = ParkingZone.DefaultParkingZoneId, locationUTM = locationUTM, @@ -126,12 +116,8 @@ object ParkingStall { * @param parkingAlternative Parking Alternative * @return */ - def fromParkingAlternative[GEO](tazId: Id[TAZ], parkingAlternative: ParkingAlternative[GEO])(implicit - gl: GeoLevel[GEO] - ): ParkingStall = { - import GeoLevel.ops._ + def fromParkingAlternative(tazId: Id[TAZ], parkingAlternative: ParkingAlternative): ParkingStall = { ParkingStall( - parkingAlternative.geo.getId, tazId, parkingAlternative.parkingZone.parkingZoneId, parkingAlternative.coord, diff --git a/src/main/scala/beam/agentsim/infrastructure/ZonalParkingManager.scala b/src/main/scala/beam/agentsim/infrastructure/ZonalParkingManager.scala index a540be12174..296f62d9725 100755 --- a/src/main/scala/beam/agentsim/infrastructure/ZonalParkingManager.scala +++ b/src/main/scala/beam/agentsim/infrastructure/ZonalParkingManager.scala @@ -1,25 +1,19 @@ package beam.agentsim.infrastructure -import beam.agentsim.infrastructure.parking.ParkingZoneSearch.ZoneSearchTree import beam.agentsim.infrastructure.parking._ import beam.agentsim.infrastructure.taz.TAZ import beam.sim.BeamServices import beam.sim.config.BeamConfig import com.typesafe.scalalogging.LazyLogging import com.vividsolutions.jts.geom.Envelope -import org.matsim.api.core.v01.network.Link import org.matsim.api.core.v01.{Coord, Id} import org.matsim.core.utils.collections.QuadTree import scala.util.Random -class ZonalParkingManager[GEO: GeoLevel](parkingZones: Map[Id[ParkingZoneId], ParkingZone[GEO]]) - extends ParkingNetwork[GEO](parkingZones) { +class ZonalParkingManager(parkingZones: Map[Id[ParkingZoneId], ParkingZone]) extends ParkingNetwork(parkingZones) { - protected val parkingZoneTree: ZoneSearchTree[GEO] = - ParkingZoneFileUtils.createZoneSearchTree(parkingZones.values.toSeq) - - override protected val searchFunctions: Option[InfrastructureFunctions[GEO]] = None + override protected val searchFunctions: Option[InfrastructureFunctions] = None } object ZonalParkingManager extends LazyLogging { @@ -36,11 +30,10 @@ object ZonalParkingManager extends LazyLogging { * * @return an instance of the ZonalParkingManager class */ - def apply[GEO: GeoLevel]( - parkingZones: Map[Id[ParkingZoneId], ParkingZone[GEO]], - geoQuadTree: QuadTree[GEO], - idToGeoMapping: scala.collection.Map[Id[GEO], GEO], - geoToTAZ: GEO => TAZ, + def apply( + parkingZones: Map[Id[ParkingZoneId], ParkingZone], + geoQuadTree: QuadTree[TAZ], + idToGeoMapping: scala.collection.Map[Id[TAZ], TAZ], distanceFunction: (Coord, Coord) => Double, boundingBox: Envelope, minSearchRadius: Double, @@ -49,18 +42,17 @@ object ZonalParkingManager extends LazyLogging { minNumberOfSameTypeZones: Int, seed: Int, mnlParkingConfig: BeamConfig.Beam.Agentsim.Agents.Parking.MulitnomialLogit - ): ZonalParkingManager[GEO] = { + ): ZonalParkingManager = { new ZonalParkingManager(parkingZones) { if (maxSearchRadius < minSearchRadius) { logger.warn( s"maxSearchRadius of $maxSearchRadius meters provided from config is less than the fixed minimum search radius of $minSearchRadius; no searches will occur with these settings." ) } - override val searchFunctions: Option[InfrastructureFunctions[GEO]] = Some( + override val searchFunctions: Option[InfrastructureFunctions] = Some( new ParkingFunctions( geoQuadTree, idToGeoMapping, - geoToTAZ, parkingZones, distanceFunction, minSearchRadius, @@ -82,20 +74,18 @@ object ZonalParkingManager extends LazyLogging { * * @return an instance of the ZonalParkingManager class */ - def apply[GEO: GeoLevel]( - parkingZones: Map[Id[ParkingZoneId], ParkingZone[GEO]], - geoQuadTree: QuadTree[GEO], - idToGeoMapping: scala.collection.Map[Id[GEO], GEO], - geoToTAZ: GEO => TAZ, + def apply( + parkingZones: Map[Id[ParkingZoneId], ParkingZone], + geoQuadTree: QuadTree[TAZ], + idToGeoMapping: scala.collection.Map[Id[TAZ], TAZ], envelopeInUTM: Envelope, beamConfig: BeamConfig, distanceFunction: (Coord, Coord) => Double - ): ZonalParkingManager[GEO] = { - ZonalParkingManager[GEO]( + ): ZonalParkingManager = { + ZonalParkingManager( parkingZones, geoQuadTree, idToGeoMapping, - geoToTAZ, distanceFunction, envelopeInUTM, beamConfig.beam.agentsim.agents.parking.minSearchRadius, @@ -115,11 +105,10 @@ object ZonalParkingManager extends LazyLogging { * @param includesHeader true if the parkingDescription includes a csv-style header * @return */ - def apply[GEO: GeoLevel]( + def apply( parkingDescription: Iterator[String], - geoQuadTree: QuadTree[GEO], - idToGeoMapping: scala.collection.Map[Id[GEO], GEO], - geoToTAZ: GEO => TAZ, + geoQuadTree: QuadTree[TAZ], + idToGeoMapping: scala.collection.Map[Id[TAZ], TAZ], boundingBox: Envelope, distanceFunction: (Coord, Coord) => Double, minSearchRadius: Double, @@ -128,18 +117,17 @@ object ZonalParkingManager extends LazyLogging { mnlParkingConfig: BeamConfig.Beam.Agentsim.Agents.Parking.MulitnomialLogit, beamConfig: BeamConfig, beamServicesMaybe: Option[BeamServices] - ): ZonalParkingManager[GEO] = { + ): ZonalParkingManager = { val parking = ParkingZoneFileUtils.fromIterator( parkingDescription, Some(beamConfig), beamServicesMaybe, new Random(seed) ) - ZonalParkingManager[GEO]( + ZonalParkingManager( parking.zones.filter(_._2.chargingPointType.isEmpty).toMap, geoQuadTree, idToGeoMapping, - geoToTAZ, distanceFunction, boundingBox, minSearchRadius, @@ -157,42 +145,18 @@ object ZonalParkingManager extends LazyLogging { * @return an instance of the ZonalParkingManager class */ def init( - parkingZones: Map[Id[ParkingZoneId], ParkingZone[TAZ]], + parkingZones: Map[Id[ParkingZoneId], ParkingZone], envelopeInUTM: Envelope, beamServices: BeamServices - ): ZonalParkingManager[TAZ] = { - ZonalParkingManager[TAZ]( + ): ZonalParkingManager = { + ZonalParkingManager( parkingZones, beamServices.beamScenario.tazTreeMap.tazQuadTree, beamServices.beamScenario.tazTreeMap.idToTAZMapping, - identity[TAZ](_), envelopeInUTM, beamServices.beamConfig, beamServices.geo.distUTMInMeters(_, _) ) } - /** - * constructs a ZonalParkingManager with provided parkingZones - * - * @return an instance of the ZonalParkingManager class - */ - def init( - parkingZones: Map[Id[ParkingZoneId], ParkingZone[Link]], - geoQuadTree: QuadTree[Link], - idToGeoMapping: scala.collection.Map[Id[Link], Link], - geoToTAZ: Link => TAZ, - envelopeInUTM: Envelope, - beamServices: BeamServices - ): ZonalParkingManager[Link] = { - ZonalParkingManager[Link]( - parkingZones, - geoQuadTree, - idToGeoMapping, - geoToTAZ, - envelopeInUTM, - beamServices.beamConfig, - beamServices.geo.distUTMInMeters(_, _) - ) - } } diff --git a/src/main/scala/beam/agentsim/infrastructure/parking/GeoLevel.scala b/src/main/scala/beam/agentsim/infrastructure/parking/GeoLevel.scala deleted file mode 100644 index 507c9cad23a..00000000000 --- a/src/main/scala/beam/agentsim/infrastructure/parking/GeoLevel.scala +++ /dev/null @@ -1,75 +0,0 @@ -package beam.agentsim.infrastructure.parking - -import beam.agentsim.infrastructure.parking.ParkingStallSampling.GeoSampling -import beam.agentsim.infrastructure.taz.TAZ -import beam.router.BeamRouter.Location -import org.matsim.api.core.v01.{Coord, Id} -import org.matsim.api.core.v01.network.Link - -import scala.util.Random - -trait GeoLevel[A] { - def getId(a: A): Id[A] - def centroidLocation(a: A): Coord - def parseId(strId: String): Id[A] - def emergencyGeoId: Id[A] - def defaultGeoId: Id[A] - def geoSampling: GeoSampling[A] -} - -object GeoLevel { - - def apply[A](implicit gl: GeoLevel[A]): GeoLevel[A] = gl - - object ops { - def getId[A: GeoLevel](a: A): Id[A] = GeoLevel[A].getId(a) - - implicit class GeoLevelOps[A](val a: A) extends AnyVal { - def getId(implicit gl: GeoLevel[A]): Id[A] = gl.getId(a) - def centroidLocation(implicit gl: GeoLevel[A]): Coord = gl.centroidLocation(a) - } - } - - implicit val tazGeoLevel: GeoLevel[TAZ] = new GeoLevel[TAZ] { - override def getId(a: TAZ): Id[TAZ] = a.tazId - - override def parseId(strId: String): Id[TAZ] = Id.create(strId, classOf[TAZ]) - - override def emergencyGeoId: Id[TAZ] = TAZ.EmergencyTAZId - - override def defaultGeoId: Id[TAZ] = TAZ.DefaultTAZId - - override def geoSampling: GeoSampling[TAZ] = ParkingStallSampling.availabilityAwareSampling - - override def centroidLocation(a: TAZ): Location = a.coord - } - - implicit val linkGeoLevel: GeoLevel[Link] = new GeoLevel[Link] { - override def getId(a: Link): Id[Link] = a.getId - - override def parseId(strId: String): Id[Link] = Id.create(strId, classOf[Link]) - - override def emergencyGeoId: Id[Link] = LinkLevelOperations.EmergencyLinkId - - override def defaultGeoId: Id[Link] = LinkLevelOperations.DefaultLinkId - - override def geoSampling: GeoSampling[Link] = (_: Random, _: Location, link: Link, _: Double, _: Boolean) => - link.getCoord - - override def centroidLocation(a: Link): Location = a.getCoord - } - - /** - * This method can be used to get the special geo ids at runtime - * @param geoLevel the geo level ("TAZ", "Link") - * @return a tuple (emergency id, default id) - */ - def getSpecialGeoIds(geoLevel: String): (Id[_], Id[_]) = { - geoLevel.toLowerCase match { - case "taz" => (TAZ.EmergencyTAZId, TAZ.DefaultTAZId) - case "link" => (LinkLevelOperations.EmergencyLinkId, LinkLevelOperations.DefaultLinkId) - case _ => - throw new IllegalArgumentException(s"Unsupported parking level type $geoLevel, only TAZ | Link are supported") - } - } -} diff --git a/src/main/scala/beam/agentsim/infrastructure/parking/LinkLevelOperations.scala b/src/main/scala/beam/agentsim/infrastructure/parking/LinkLevelOperations.scala deleted file mode 100644 index b7bb2bb5619..00000000000 --- a/src/main/scala/beam/agentsim/infrastructure/parking/LinkLevelOperations.scala +++ /dev/null @@ -1,27 +0,0 @@ -package beam.agentsim.infrastructure.parking - -import beam.agentsim.infrastructure.taz.{TAZ, TAZTreeMap} -import beam.utils.matsim_conversion.ShapeUtils -import beam.utils.matsim_conversion.ShapeUtils.HasCoord -import org.matsim.api.core.v01.Id -import org.matsim.api.core.v01.network.{Link, Network} -import org.matsim.core.utils.collections.QuadTree - -import scala.collection.JavaConverters._ - -object LinkLevelOperations { - implicit val linkHasCoord: HasCoord[Link] = (a: Link) => a.getCoord - - def getLinkTreeMap(links: Seq[Link]): QuadTree[Link] = { - ShapeUtils.quadTree(links) - } - - def getLinkIdMapping(network: Network): Map[Id[Link], Link] = network.getLinks.asScala.toMap - - def getLinkToTazMapping(network: Network, tazTreeMap: TAZTreeMap): Map[Link, TAZ] = { - network.getLinks.values().asScala.map(link => link -> tazTreeMap.getTAZ(link.getCoord)).toMap - } - - val DefaultLinkId: Id[Link] = Id.createLinkId("default") - val EmergencyLinkId: Id[Link] = Id.createLinkId("emergency") -} diff --git a/src/main/scala/beam/agentsim/infrastructure/parking/ParkingNetwork.scala b/src/main/scala/beam/agentsim/infrastructure/parking/ParkingNetwork.scala index 2c2531b9a47..732cb4515ff 100644 --- a/src/main/scala/beam/agentsim/infrastructure/parking/ParkingNetwork.scala +++ b/src/main/scala/beam/agentsim/infrastructure/parking/ParkingNetwork.scala @@ -6,11 +6,10 @@ import beam.utils.metrics.SimpleCounter import com.typesafe.scalalogging.LazyLogging import org.matsim.api.core.v01.Id -abstract class ParkingNetwork[GEO: GeoLevel](parkingZones: Map[Id[ParkingZoneId], ParkingZone[GEO]]) - extends LazyLogging { +abstract class ParkingNetwork(parkingZones: Map[Id[ParkingZoneId], ParkingZone]) extends LazyLogging { // Generic - protected val searchFunctions: Option[InfrastructureFunctions[GEO]] + protected val searchFunctions: Option[InfrastructureFunctions] // Core protected var totalStallsInUse: Long = 0L diff --git a/src/main/scala/beam/agentsim/infrastructure/parking/ParkingStallSampling.scala b/src/main/scala/beam/agentsim/infrastructure/parking/ParkingStallSampling.scala index b4f8c3fbf68..10cc2fd6691 100644 --- a/src/main/scala/beam/agentsim/infrastructure/parking/ParkingStallSampling.scala +++ b/src/main/scala/beam/agentsim/infrastructure/parking/ParkingStallSampling.scala @@ -10,7 +10,6 @@ import org.matsim.api.core.v01.Coord */ object ParkingStallSampling { - type GeoSampling[GEO] = (Random, Location, GEO, Double, Boolean) => Location val maxOffsetDistance = 600.0 // TODO: Make this a config parameter /** diff --git a/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZone.scala b/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZone.scala index 054d834c2ca..257c720b22b 100644 --- a/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZone.scala +++ b/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZone.scala @@ -4,6 +4,7 @@ import beam.agentsim.agents.vehicles.VehicleCategory.VehicleCategory import beam.agentsim.agents.vehicles.VehicleManager import beam.agentsim.agents.vehicles.VehicleManager.ReservedFor import beam.agentsim.infrastructure.charging.ChargingPointType +import beam.agentsim.infrastructure.taz.TAZ import com.typesafe.scalalogging.LazyLogging import org.matsim.api.core.v01.Id import org.matsim.api.core.v01.network.Link @@ -21,9 +22,9 @@ trait ParkingZoneId * @param chargingPointType if this stall has charging, this is the type of charging * @param pricingModel if this stall has pricing, this is the type of pricing */ -class ParkingZone[GEO]( +class ParkingZone( val parkingZoneId: Id[ParkingZoneId], - val geoId: Id[GEO], + val tazId: Id[TAZ], val parkingType: ParkingType, var stallsAvailable: Int, val maxStalls: Int, @@ -53,10 +54,10 @@ class ParkingZone[GEO]( s"ParkingZone(parkingZoneId = $parkingZoneId, numStalls = $stallsAvailable, $chargeString, $pricingString)" } - def makeCopy(maxStalls: Int = -1): ParkingZone[GEO] = { + def makeCopy(maxStalls: Int = -1): ParkingZone = { new ParkingZone( this.parkingZoneId, - this.geoId, + this.tazId, this.parkingType, this.stallsAvailable, if (maxStalls == -1) this.maxStalls else maxStalls, @@ -70,8 +71,8 @@ class ParkingZone[GEO]( override def equals(that: Any): Boolean = that match { - case that: ParkingZone[_] => that.hashCode() == hashCode - case _ => false + case that: ParkingZone => that.hashCode() == hashCode + case _ => false } override def hashCode: Int = parkingZoneId.hashCode() } @@ -94,9 +95,9 @@ object ParkingZone extends LazyLogging { * @param pricingModel if this stall has pricing, this is the type of pricing * @return a new StallValues object */ - private def apply[GEO]( + private def apply( parkingZoneId: Id[ParkingZoneId], - geoId: Id[GEO], + geoId: Id[TAZ], parkingType: ParkingType, reservedFor: ReservedFor, stallsAvailable: Int = 0, @@ -105,8 +106,8 @@ object ParkingZone extends LazyLogging { pricingModel: Option[PricingModel] = None, timeRestrictions: Map[VehicleCategory, Range] = Map.empty, link: Option[Link] = None - ): ParkingZone[GEO] = - new ParkingZone[GEO]( + ): ParkingZone = + new ParkingZone( parkingZoneId, geoId, parkingType, @@ -119,12 +120,12 @@ object ParkingZone extends LazyLogging { link ) - def defaultInit[GEO]( - geoId: Id[GEO], + def defaultInit( + geoId: Id[TAZ], parkingType: ParkingType, numStalls: Int - ): ParkingZone[GEO] = { - init[GEO]( + ): ParkingZone = { + init( Some(DefaultParkingZoneId), geoId, parkingType, @@ -133,9 +134,9 @@ object ParkingZone extends LazyLogging { ) } - def init[GEO]( + def init( parkingZoneIdMaybe: Option[Id[ParkingZoneId]], - geoId: Id[GEO], + geoId: Id[TAZ], parkingType: ParkingType, reservedFor: ReservedFor, maxStalls: Int = 0, @@ -143,13 +144,13 @@ object ParkingZone extends LazyLogging { pricingModel: Option[PricingModel] = None, timeRestrictions: Map[VehicleCategory, Range] = Map.empty, link: Option[Link] = None - ): ParkingZone[GEO] = { + ): ParkingZone = { val parkingZoneId = parkingZoneIdMaybe match { case Some(parkingZoneId) => parkingZoneId case _ => constructParkingZoneKey(reservedFor, geoId, parkingType, chargingPointType, pricingModel, maxStalls) } - ParkingZone[GEO]( + ParkingZone( parkingZoneId, geoId, parkingType, @@ -169,7 +170,7 @@ object ParkingZone extends LazyLogging { * @param parkingZone the object to increment * @return True|False (representing success) wrapped in an effect type */ - def releaseStall[GEO](parkingZone: ParkingZone[GEO]): Boolean = + def releaseStall(parkingZone: ParkingZone): Boolean = if (parkingZone.parkingZoneId == DefaultParkingZoneId) { // this zone does not exist in memory but it has infinitely many stalls to release true @@ -187,7 +188,7 @@ object ParkingZone extends LazyLogging { * @param parkingZone the object to increment * @return True|False (representing success) wrapped in an effect type */ - def claimStall[GEO](parkingZone: ParkingZone[GEO]): Boolean = + def claimStall(parkingZone: ParkingZone): Boolean = if (parkingZone.parkingZoneId == DefaultParkingZoneId) { // this zone does not exist in memory but it has infinitely many stalls to release true @@ -206,10 +207,10 @@ object ParkingZone extends LazyLogging { * @param parkingZoneId an array index * @return Optional ParkingZone */ - def getParkingZone[GEO]( - parkingZones: Map[Id[ParkingZoneId], ParkingZone[GEO]], + def getParkingZone( + parkingZones: Map[Id[ParkingZoneId], ParkingZone], parkingZoneId: Id[ParkingZoneId] - ): Option[ParkingZone[GEO]] = { + ): Option[ParkingZone] = { val result = parkingZones.get(parkingZoneId) if (result.isEmpty) { logger.warn(s"attempting to access parking zone with illegal parkingZoneId $parkingZoneId, will be ignored") diff --git a/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZoneFileUtils.scala b/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZoneFileUtils.scala index 30c820cc30e..a962d8d8a2b 100644 --- a/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZoneFileUtils.scala +++ b/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZoneFileUtils.scala @@ -5,18 +5,17 @@ import beam.agentsim.agents.vehicles.VehicleManager.ReservedFor import beam.agentsim.agents.vehicles.{VehicleCategory, VehicleManager} import beam.agentsim.infrastructure.charging.ChargingPointType import beam.agentsim.infrastructure.parking.ParkingZoneSearch.ZoneSearchTree -import beam.agentsim.infrastructure.taz.{TAZ, TAZTreeMap} +import beam.agentsim.infrastructure.taz.TAZ import beam.sim.BeamServices import beam.sim.config.BeamConfig import beam.utils.csv.GenericCsvReader import beam.utils.logging.ExponentialLazyLogging +import beam.utils.matsim_conversion.MatsimPlanConversion.IdOps import beam.utils.{FileUtils, MathUtils} import org.matsim.api.core.v01.{Coord, Id} import org.matsim.core.network.NetworkUtils import org.matsim.core.utils.io.IOUtils import org.apache.commons.lang3.StringUtils.isBlank -import org.matsim.api.core.v01.network.Link -import org.matsim.core.utils.collections.QuadTree import java.io.{BufferedReader, File, IOException} import java.text.{DecimalFormat, DecimalFormatSymbols} @@ -55,8 +54,8 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { * @param maybeChargingPoint charging point type * @return a row describing infinite free parking at this TAZ */ - def defaultParkingRow[GEO]( - geoId: Id[GEO], + def defaultParkingRow( + geoId: Id[TAZ], parkingType: ParkingType, maybeChargingPoint: Option[ChargingPointType], defaultReservedFor: ReservedFor @@ -82,15 +81,15 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { * @param totalRows number of rows read * @param failedRows number of rows which failed to parse */ - case class ParkingLoadingAccumulator[GEO]( - zones: mutable.Map[Id[ParkingZoneId], ParkingZone[GEO]] = mutable.Map.empty[Id[ParkingZoneId], ParkingZone[GEO]], - tree: mutable.Map[Id[GEO], Map[ParkingType, Vector[Id[ParkingZoneId]]]] = - mutable.Map.empty[Id[GEO], Map[ParkingType, Vector[Id[ParkingZoneId]]]], + case class ParkingLoadingAccumulator( + zones: mutable.Map[Id[ParkingZoneId], ParkingZone] = mutable.Map.empty[Id[ParkingZoneId], ParkingZone], + tree: mutable.Map[Id[TAZ], Map[ParkingType, Vector[Id[ParkingZoneId]]]] = + mutable.Map.empty[Id[TAZ], Map[ParkingType, Vector[Id[ParkingZoneId]]]], totalRows: Int = 0, failedRows: Int = 0 ) { - def countFailedRow: ParkingLoadingAccumulator[GEO] = + def countFailedRow: ParkingLoadingAccumulator = this.copy( totalRows = totalRows + 1, failedRows = failedRows + 1 @@ -116,7 +115,7 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { * @param parkingType the parking type of this row * @param parkingZone the parking zone produced by this row */ - case class ParkingLoadingDataRow[GEO](tazId: Id[GEO], parkingType: ParkingType, parkingZone: ParkingZone[GEO]) + case class ParkingLoadingDataRow(tazId: Id[TAZ], parkingType: ParkingType, parkingZone: ParkingZone) /** * write the loaded set of parking and charging options to an instance parking file @@ -125,9 +124,9 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { * @param stalls the stored ParkingZones * @param writeDestinationPath a file path to write to */ - def writeParkingZoneFile[GEO]( - stallSearch: ZoneSearchTree[GEO], - stalls: Map[Id[ParkingZoneId], ParkingZone[GEO]], + def writeParkingZoneFile( + stallSearch: ZoneSearchTree[TAZ], + stalls: Map[Id[ParkingZoneId], ParkingZone], writeDestinationPath: String ): Unit = { @@ -194,14 +193,14 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { * @param filePath location in FS of taz parking data file (.csv) * @return table and tree */ - def fromFile[GEO: GeoLevel]( + def fromFile( filePath: String, rand: Random, beamConfig: Option[BeamConfig], beamServices: Option[BeamServices], parkingStallCountScalingFactor: Double = 1.0, parkingCostScalingFactor: Double = 1.0 - ): (Map[Id[ParkingZoneId], ParkingZone[GEO]], ZoneSearchTree[GEO]) = { + ): (Map[Id[ParkingZoneId], ParkingZone], ZoneSearchTree[TAZ]) = { val parkingLoadingAccumulator = fromFileToAccumulator( filePath, @@ -222,15 +221,15 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { * @param filePath location in FS of taz parking data file (.csv) * @return parking zone accumulator */ - def fromFileToAccumulator[GEO: GeoLevel]( + def fromFileToAccumulator( filePath: String, rand: Random, beamConfig: Option[BeamConfig], beamServices: Option[BeamServices], parkingStallCountScalingFactor: Double = 1.0, parkingCostScalingFactor: Double = 1.0, - parkingLoadingAcc: ParkingLoadingAccumulator[GEO] = ParkingLoadingAccumulator[GEO]() - ): ParkingLoadingAccumulator[GEO] = { + parkingLoadingAcc: ParkingLoadingAccumulator = ParkingLoadingAccumulator() + ): ParkingLoadingAccumulator = { FileUtils.using(FileUtils.getReader(filePath)) { reader => Try( fromBufferedReader( @@ -264,21 +263,21 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { * @param reader a java.io.BufferedReader of a csv file * @return ParkingZone array and tree lookup */ - def fromBufferedReader[GEO: GeoLevel]( + def fromBufferedReader( reader: BufferedReader, rand: Random, beamConfig: Option[BeamConfig], beamServices: Option[BeamServices], parkingStallCountScalingFactor: Double = 1.0, parkingCostScalingFactor: Double = 1.0, - parkingLoadingAccumulator: ParkingLoadingAccumulator[GEO] = ParkingLoadingAccumulator() - ): ParkingLoadingAccumulator[GEO] = { + parkingLoadingAccumulator: ParkingLoadingAccumulator = ParkingLoadingAccumulator() + ): ParkingLoadingAccumulator = { val (iterator, closable) = GenericCsvReader.readFromReaderAs[jMap](reader, identity) @tailrec def _read( - accumulator: ParkingLoadingAccumulator[GEO] - ): ParkingLoadingAccumulator[GEO] = { + accumulator: ParkingLoadingAccumulator + ): ParkingLoadingAccumulator = { if (iterator.hasNext) { val csvRow = iterator.next() val updatedAccumulator = parseParkingZoneFromRow( @@ -293,7 +292,7 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { ) match { case None => accumulator.countFailedRow - case Some(row: ParkingLoadingDataRow[GEO]) => + case Some(row: ParkingLoadingDataRow) => addStallToSearch(row, accumulator) } _read(updatedAccumulator) @@ -315,7 +314,7 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { * @param csvFileContents each line from a file to be read * @return table and search tree */ - def fromIterator[GEO: GeoLevel]( + def fromIterator( csvFileContents: Iterator[String], beamConfig: Option[BeamConfig], beamServices: Option[BeamServices], @@ -323,8 +322,8 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { defaultReservedFor: Option[ReservedFor] = None, parkingStallCountScalingFactor: Double = 1.0, parkingCostScalingFactor: Double = 1.0, - parkingLoadingAcc: ParkingLoadingAccumulator[GEO] = ParkingLoadingAccumulator[GEO]() - ): ParkingLoadingAccumulator[GEO] = { + parkingLoadingAcc: ParkingLoadingAccumulator = ParkingLoadingAccumulator() + ): ParkingLoadingAccumulator = { val withLineBreaks = csvFileContents.filterNot(_.trim.isEmpty).flatMap(x => Seq(x, "\n")) val (iterator, closable) = @@ -345,7 +344,7 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { ) match { case None => accumulator.countFailedRow - case Some(row: ParkingLoadingDataRow[GEO]) => + case Some(row: ParkingLoadingDataRow) => addStallToSearch(row, accumulator) } } match { @@ -361,29 +360,6 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { } } - /** - * Creating search tree to find stalls from a sequence of Parking zones - * - * @param zones each line from a file to be read - * @return table and search tree - */ - def createZoneSearchTree[GEO](zones: Seq[ParkingZone[GEO]]): ZoneSearchTree[GEO] = { - - zones.foldLeft(Map.empty: ZoneSearchTree[GEO]) { (accumulator, zone) => - val parkingTypes = accumulator.getOrElse(zone.geoId, Map()) - val parkingZoneIds: Vector[Id[ParkingZoneId]] = - parkingTypes.getOrElse(zone.parkingType, Vector.empty[Id[ParkingZoneId]]) - - accumulator.updated( - zone.geoId, - parkingTypes.updated( - zone.parkingType, - (parkingZoneIds :+ zone.parkingZoneId).sorted - ) - ) - } - } - private val TimeRestriction = """(\w+)\|(\d{1,2})(?::(\d{2}))?-(\d{1,2})(?::(\d{2}))?""".r private[parking] def parseTimeRestrictions(timeRestrictionsString: String): Map[VehicleCategory, Range] = { @@ -450,7 +426,7 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { * @param csvRow the comma-separated parking attributes * @return a ParkingZone and it's corresponding ParkingType and Taz Id */ - def parseParkingZoneFromRow[GEO: GeoLevel]( + def parseParkingZoneFromRow( csvRow: jMap, rowNumber: Int, rand: Random, @@ -459,7 +435,7 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { defaultReservedFor: Option[ReservedFor] = None, parkingStallCountScalingFactor: Double = 1.0, parkingCostScalingFactor: Double = 1.0 - ): Option[ParkingLoadingDataRow[GEO]] = { + ): Option[ParkingLoadingDataRow] = { if (!validateCsvRow(csvRow)) { logger.error(s"Failed to match row of parking configuration '$csvRow' to expected schema") return None @@ -481,7 +457,7 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { val newCostInDollarsString = (feeInCents * parkingCostScalingFactor / 100.0).toString val reservedFor = validateReservedFor(reservedForString, beamConfig, defaultReservedFor) // parse this row from the source file - val taz = GeoLevel[GEO].parseId(tazString.toUpperCase) + val taz = tazString.toUpperCase.createId[TAZ] val parkingType = ParkingType(parkingTypeString) val pricingModel = PricingModel(pricingModelString, newCostInDollarsString) val timeRestrictions = parseTimeRestrictions(timeRestrictionsString) @@ -576,10 +552,10 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { * @param accumulator the currently loaded zones and search tree * @return updated tree, stalls */ - private[ParkingZoneFileUtils] def addStallToSearch[GEO]( - row: ParkingLoadingDataRow[GEO], - accumulator: ParkingLoadingAccumulator[GEO] - ): ParkingLoadingAccumulator[GEO] = { + private[ParkingZoneFileUtils] def addStallToSearch( + row: ParkingLoadingDataRow, + accumulator: ParkingLoadingAccumulator + ): ParkingLoadingAccumulator = { // find any data stored already within this TAZ and with this ParkingType val parkingTypes = accumulator.tree.getOrElse(row.tazId, Map()) @@ -601,50 +577,18 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { ParkingLoadingAccumulator(accumulator.zones, accumulator.tree, accumulator.totalRows + 1, accumulator.failedRows) } - def generateLinkParkingOutOfTazParking( - tazZones: Map[Id[ParkingZoneId], ParkingZone[TAZ]], - linkQuadTree: QuadTree[Link], - linkToTAZMapping: Map[Link, TAZ], - tazTreeMap: TAZTreeMap - ): Map[Id[ParkingZoneId], ParkingZone[Link]] = { - val tazToLinksMapping = linkToTAZMapping.groupBy { case (_, taz) => taz.tazId }.mapValues(_.keys.toIndexedSeq) - val random = new Random() - tazZones.mapValues { zone => - val links = tazToLinksMapping.getOrElse( - zone.geoId, { - val taz = tazTreeMap.getTAZ(zone.geoId).get - val link = linkQuadTree.getClosest(taz.coord.getX, taz.coord.getY) - IndexedSeq(link) - } - ) - val link = zone.link.getOrElse(MathUtils.selectRandomElement(links, random)) - new ParkingZone[Link]( - zone.parkingZoneId, - link.getId, - zone.parkingType, - zone.stallsAvailable, - zone.maxStalls, - zone.reservedFor, - zone.chargingPointType, - zone.pricingModel, - zone.timeRestrictions, - Some(link) - ) - } - } - /** * generates ubiquitous parking from a taz centers file, such as test/input/beamville/taz-centers.csv * @param geoObjects geo objects that should be used to hold parking stalls * @param parkingTypes the parking types we are generating, by default, the complete set * @return */ - def generateDefaultParkingFromGeoObjects[GEO: GeoLevel]( - geoObjects: Iterable[GEO], + def generateDefaultParkingFromGeoObjects( + geoObjects: Iterable[TAZ], random: Random, defaultReservedFor: ReservedFor, parkingTypes: Seq[ParkingType] = ParkingType.AllTypes - ): (Map[Id[ParkingZoneId], ParkingZone[GEO]], ZoneSearchTree[GEO]) = { + ): (Map[Id[ParkingZoneId], ParkingZone], ZoneSearchTree[TAZ]) = { val parkingLoadingAccumulator = generateDefaultParkingAccumulatorFromGeoObjects( geoObjects, @@ -661,13 +605,13 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { * @param parkingTypes the parking types we are generating, by default, the complete set * @return the parking accumulator */ - def generateDefaultParkingAccumulatorFromGeoObjects[GEO: GeoLevel]( - geoObjects: Iterable[GEO], + def generateDefaultParkingAccumulatorFromGeoObjects( + geoObjects: Iterable[TAZ], random: Random, defaultReservedFor: ReservedFor, parkingTypes: Seq[ParkingType] = ParkingType.AllTypes, - parkingLoadingAcc: ParkingLoadingAccumulator[GEO] = ParkingLoadingAccumulator[GEO]() - ): ParkingLoadingAccumulator[GEO] = { + parkingLoadingAcc: ParkingLoadingAccumulator = ParkingLoadingAccumulator() + ): ParkingLoadingAccumulator = { val result = generateDefaultParking(geoObjects, random, defaultReservedFor, parkingTypes, parkingLoadingAcc) logger.info( @@ -685,13 +629,13 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { * @param parkingTypes the parking types we are generating, by default, the complete set * @return parking zones and parking search tree */ - def generateDefaultParking[GEO: GeoLevel]( - geoObjects: Iterable[GEO], + def generateDefaultParking( + geoObjects: Iterable[TAZ], random: Random, defaultReservedFor: ReservedFor, parkingTypes: Seq[ParkingType] = ParkingType.AllTypes, - parkingLoadingAcc: ParkingLoadingAccumulator[GEO] = ParkingLoadingAccumulator[GEO]() - ): ParkingLoadingAccumulator[GEO] = { + parkingLoadingAcc: ParkingLoadingAccumulator = ParkingLoadingAccumulator() + ): ParkingLoadingAccumulator = { val rows: Iterable[String] = for { geoObj <- geoObjects @@ -700,8 +644,7 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { // None is `NoCharger` which will allow non-charger ParkingZones. Check `returnSpotsWithoutChargers` in `ZonalParkingManager` maybeChargingPoint <- Seq(Some(ChargingPointType.CustomChargingPoint("DCFast", "50", "DC")), None) // NoCharger } yield { - import GeoLevel.ops._ - defaultParkingRow(geoObj.getId, parkingType, maybeChargingPoint, defaultReservedFor) + defaultParkingRow(geoObj.tazId, parkingType, maybeChargingPoint, defaultReservedFor) } val withHeader = Iterator.single(ParkingFileHeader) ++ rows @@ -712,14 +655,14 @@ object ParkingZoneFileUtils extends ExponentialLazyLogging { * Write parking zones to csv. */ @SuppressWarnings(Array("UnusedMethodParameter")) // TODO: scapegoat bug? - def toCsv[GEO: GeoLevel](parkingZones: Map[Id[ParkingZoneId], ParkingZone[GEO]], filePath: String): Unit = { + def toCsv(parkingZones: Map[Id[ParkingZoneId], ParkingZone], filePath: String): Unit = { val df = new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.ENGLISH)) df.setMaximumFractionDigits(7) val fileContent = parkingZones.values.toIndexedSeq .sortBy(_.parkingZoneId) .map { parkingZone => List( - parkingZone.geoId, + parkingZone.tazId, parkingZone.parkingType, parkingZone.pricingModel.getOrElse(""), parkingZone.chargingPointType.getOrElse(""), diff --git a/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZoneSearch.scala b/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZoneSearch.scala index acd6a85f2a2..2e1bf91b185 100644 --- a/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZoneSearch.scala +++ b/src/main/scala/beam/agentsim/infrastructure/parking/ParkingZoneSearch.scala @@ -68,14 +68,14 @@ object ParkingZoneSearch { * @param zoneQuadTree [[ParkingZone]]s are associated with a TAZ, which are themselves stored in this Quad Tree * @param random random number generator */ - case class ParkingZoneSearchParams[GEO]( + case class ParkingZoneSearchParams( destinationUTM: Location, parkingDuration: Double, searchMode: ParkingSearchMode, parkingMNLConfig: ParkingMNL.ParkingMNLConfig, - zoneCollections: Map[Id[GEO], ParkingZoneCollection[GEO]], - parkingZones: Map[Id[ParkingZoneId], ParkingZone[GEO]], - zoneQuadTree: QuadTree[GEO], + zoneCollections: Map[Id[TAZ], ParkingZoneCollection], + parkingZones: Map[Id[ParkingZoneId], ParkingZone], + zoneQuadTree: QuadTree[TAZ], random: Random, originUTM: Option[Location], reservedFor: ReservedFor @@ -88,9 +88,9 @@ object ParkingZoneSearch { * @param parkingZone the [[ParkingZone]] associated with this stall * @param parkingZoneIdsSeen list of [[ParkingZone]] ids that were seen in this search */ - case class ParkingZoneSearchResult[GEO]( + case class ParkingZoneSearchResult( parkingStall: ParkingStall, - parkingZone: ParkingZone[GEO], + parkingZone: ParkingZone, parkingZoneIdsSeen: List[Id[ParkingZoneId]] = List.empty, parkingZonesSampled: List[(Id[ParkingZoneId], Option[ChargingPointType], ParkingType, Double)] = List.empty, iterations: Int = 1 @@ -106,10 +106,10 @@ object ParkingZoneSearch { * @param coord location sampled for this alternative * @param costInDollars expected cost for using this alternative */ - case class ParkingAlternative[GEO]( - geo: GEO, + case class ParkingAlternative( + geo: TAZ, parkingType: ParkingType, - parkingZone: ParkingZone[GEO], + parkingZone: ParkingZone, coord: Coord, costInDollars: Double ) @@ -120,8 +120,8 @@ object ParkingZoneSearch { * @param parkingAlternative ParkingAlternative * @param utilityParameters Map[ParkingMNL.Parameters, Double] */ - private[ParkingZoneSearch] case class ParkingSearchAlternative[GEO]( - parkingAlternative: ParkingAlternative[GEO], + private[ParkingZoneSearch] case class ParkingSearchAlternative( + parkingAlternative: ParkingAlternative, utilityParameters: Map[ParkingMNL.Parameters, Double] ) @@ -135,32 +135,30 @@ object ParkingZoneSearch { * @param parkingZoneMNLParamsFunction a function that generates MNL parameters for a [[ParkingAlternative]] * @return if found, a suitable [[ParkingAlternative]] */ - def incrementalParkingZoneSearch[GEO: GeoLevel]( + def incrementalParkingZoneSearch( config: ParkingZoneSearchConfiguration, - params: ParkingZoneSearchParams[GEO], - parkingZoneFilterFunction: ParkingZone[GEO] => Boolean, - parkingZoneLocSamplingFunction: ParkingZone[GEO] => Coord, - parkingZoneMNLParamsFunction: ParkingAlternative[GEO] => Map[ParkingMNL.Parameters, Double], - geoToTAZ: GEO => TAZ - ): Option[ParkingZoneSearchResult[GEO]] = { - import GeoLevel.ops._ + params: ParkingZoneSearchParams, + parkingZoneFilterFunction: ParkingZone => Boolean, + parkingZoneLocSamplingFunction: ParkingZone => Coord, + parkingZoneMNLParamsFunction: ParkingAlternative => Map[ParkingMNL.Parameters, Double] + ): Option[ParkingZoneSearchResult] = { // find zones @tailrec def _search( - searchMode: SearchMode[GEO], + searchMode: SearchMode, parkingZoneIdsSeen: List[Id[ParkingZoneId]] = List.empty, parkingZoneIdsSampled: List[(Id[ParkingZoneId], Option[ChargingPointType], ParkingType, Double)] = List.empty, iterations: Int = 1 - ): Option[ParkingZoneSearchResult[GEO]] = { + ): Option[ParkingZoneSearchResult] = { // a lookup of the (next) search ring for TAZs searchMode.lookupParkingZonesInNextSearchAreaUnlessThresholdReached(params.zoneQuadTree) match { case Some(theseZones) => // ParkingZones as as ParkingAlternatives - val alternatives: List[ParkingSearchAlternative[GEO]] = { + val alternatives: List[ParkingSearchAlternative] = { for { zone <- theseZones - zoneCollection <- params.zoneCollections.get(zone.getId).toSeq + zoneCollection <- params.zoneCollections.get(zone.tazId).toSeq parkingZone <- zoneCollection.getFreeZones( config.fractionOfSameTypeZones, config.minNumberOfSameTypeZones, @@ -179,7 +177,7 @@ object ParkingZoneSearch { case Some(pricingModel) => PricingModel.evaluateParkingTicket(pricingModel, params.parkingDuration.toInt) } - val parkingAlternative: ParkingAlternative[GEO] = + val parkingAlternative: ParkingAlternative = ParkingAlternative(zone, parkingZone.parkingType, parkingZone, stallLocation, stallPriceInDollars) val parkingAlternativeUtility: Map[ParkingMNL.Parameters, Double] = parkingZoneMNLParamsFunction(parkingAlternative) @@ -194,12 +192,12 @@ object ParkingZoneSearch { _search(searchMode, parkingZoneIdsSeen, parkingZoneIdsSampled, iterations + 1) } else { // remove any invalid parking alternatives - val alternativesToSample: Map[ParkingAlternative[GEO], Map[ParkingMNL.Parameters, Double]] = + val alternativesToSample: Map[ParkingAlternative, Map[ParkingMNL.Parameters, Double]] = alternatives.map { a => a.parkingAlternative -> a.utilityParameters }.toMap - val mnl: MultinomialLogit[ParkingAlternative[GEO], ParkingMNL.Parameters] = + val mnl: MultinomialLogit[ParkingAlternative, ParkingMNL.Parameters] = MultinomialLogit( Map.empty, params.parkingMNLConfig @@ -210,8 +208,7 @@ object ParkingZoneSearch { // create a new stall instance. you win! val parkingStall = ParkingStall( - taz.getId, - geoToTAZ(taz).getId, + taz.tazId, parkingZone.parkingZoneId, coordinate, costInDollars, @@ -268,7 +265,7 @@ object ParkingZoneSearch { object ParkingZoneInfo { - def describeParkingZone(zone: ParkingZone[_]): ParkingZoneInfo = { + def describeParkingZone(zone: ParkingZone): ParkingZoneInfo = { new ParkingZoneInfo( zone.parkingType, zone.chargingPointType, @@ -278,9 +275,9 @@ object ParkingZoneSearch { } } - class ParkingZoneCollection[GEO](parkingZones: Seq[ParkingZone[GEO]]) { + class ParkingZoneCollection(val parkingZones: Seq[ParkingZone]) { - private val publicFreeZones: Map[ParkingZoneInfo, mutable.Set[ParkingZone[GEO]]] = + private val publicFreeZones: Map[ParkingZoneInfo, mutable.Set[ParkingZone]] = parkingZones.view .filter(_.reservedFor.managerType == TypeEnum.Default) .groupBy(ParkingZoneInfo.describeParkingZone) @@ -288,7 +285,7 @@ object ParkingZoneSearch { .view .force - private val reservedFreeZones: Map[ReservedFor, mutable.Set[ParkingZone[GEO]]] = + private val reservedFreeZones: Map[ReservedFor, mutable.Set[ParkingZone]] = parkingZones.view .filter(_.reservedFor.managerType != TypeEnum.Default) .groupBy(_.reservedFor) @@ -301,7 +298,7 @@ object ParkingZoneSearch { min: Int, reservedFor: ReservedFor, rnd: Random - ): IndexedSeq[ParkingZone[GEO]] = { + ): IndexedSeq[ParkingZone] = { ( publicFreeZones.view.flatMap { case (_, zones) => val numToTake = Math.max(MathUtils.doubleToInt(zones.size * fraction), min) @@ -311,17 +308,17 @@ object ParkingZoneSearch { ).toIndexedSeq } - def claimZone(parkingZone: ParkingZone[GEO]): Unit = + def claimZone(parkingZone: ParkingZone): Unit = if (parkingZone.stallsAvailable <= 0) { for (set <- getCorrespondingZoneSet(parkingZone)) set -= parkingZone } - def releaseZone(parkingZone: ParkingZone[GEO]): Unit = + def releaseZone(parkingZone: ParkingZone): Unit = if (parkingZone.stallsAvailable > 0) { for (set <- getCorrespondingZoneSet(parkingZone)) set += parkingZone } - private def getCorrespondingZoneSet(parkingZone: ParkingZone[GEO]): Option[mutable.Set[ParkingZone[GEO]]] = + private def getCorrespondingZoneSet(parkingZone: ParkingZone): Option[mutable.Set[ParkingZone]] = if (parkingZone.reservedFor.managerType == TypeEnum.Default) { publicFreeZones.get(ParkingZoneInfo.describeParkingZone(parkingZone)) } else { @@ -329,28 +326,28 @@ object ParkingZoneSearch { } } - def createZoneCollections[GEO](zones: Seq[ParkingZone[GEO]]): Map[Id[GEO], ParkingZoneCollection[GEO]] = { - zones.groupBy(_.geoId).mapValues(new ParkingZoneCollection(_)).view.force + def createZoneCollections(zones: Seq[ParkingZone]): Map[Id[TAZ], ParkingZoneCollection] = { + zones.groupBy(_.tazId).mapValues(new ParkingZoneCollection(_)).view.force } - trait SearchMode[GEO] { - def lookupParkingZonesInNextSearchAreaUnlessThresholdReached(zoneQuadTree: QuadTree[GEO]): Option[List[GEO]] + trait SearchMode { + def lookupParkingZonesInNextSearchAreaUnlessThresholdReached(zoneQuadTree: QuadTree[TAZ]): Option[List[TAZ]] } object SearchMode { - case class DestinationSearch[GEO]( + case class DestinationSearch( destinationUTM: Location, searchStartRadius: Double, searchMaxRadius: Double, expansionFactor: Double - ) extends SearchMode[GEO] { + ) extends SearchMode { private var thisInnerRadius: Double = 0.0 private var thisOuterRadius: Double = searchStartRadius override def lookupParkingZonesInNextSearchAreaUnlessThresholdReached( - zoneQuadTree: QuadTree[GEO] - ): Option[List[GEO]] = { + zoneQuadTree: QuadTree[TAZ] + ): Option[List[TAZ]] = { if (thisInnerRadius > searchMaxRadius) None else { val result = zoneQuadTree @@ -364,20 +361,20 @@ object ParkingZoneSearch { } } - case class EnrouteSearch[GEO]( + case class EnrouteSearch( originUTM: Location, destinationUTM: Location, searchMaxDistanceToFociInPercent: Double, expansionFactor: Double, distanceFunction: (Coord, Coord) => Double - ) extends SearchMode[GEO] { + ) extends SearchMode { private val startDistance: Double = distanceFunction(originUTM, destinationUTM) * 1.01 private val maxDistance: Double = startDistance * searchMaxDistanceToFociInPercent private var thisInnerDistance: Double = startDistance override def lookupParkingZonesInNextSearchAreaUnlessThresholdReached( - zoneQuadTree: QuadTree[GEO] - ): Option[List[GEO]] = { + zoneQuadTree: QuadTree[TAZ] + ): Option[List[TAZ]] = { if (thisInnerDistance >= maxDistance) None else { val result = zoneQuadTree @@ -390,10 +387,10 @@ object ParkingZoneSearch { } } - def getInstance[GEO]( + def getInstance( config: ParkingZoneSearchConfiguration, - params: ParkingZoneSearchParams[GEO] - ): SearchMode[GEO] = { + params: ParkingZoneSearchParams + ): SearchMode = { params.searchMode match { case ParkingSearchMode.EnRoute => EnrouteSearch( diff --git a/src/main/scala/beam/agentsim/infrastructure/parking/TazToLinkLevelParkingApp.scala b/src/main/scala/beam/agentsim/infrastructure/parking/TazToLinkLevelParkingApp.scala deleted file mode 100644 index 8d4055e4c55..00000000000 --- a/src/main/scala/beam/agentsim/infrastructure/parking/TazToLinkLevelParkingApp.scala +++ /dev/null @@ -1,80 +0,0 @@ -package beam.agentsim.infrastructure.parking - -import beam.agentsim.infrastructure.parking.ParkingZoneSearch.ZoneSearchTree -import beam.agentsim.infrastructure.taz.{TAZ, TAZTreeMap} -import com.typesafe.scalalogging.StrictLogging -import org.matsim.api.core.v01.Id -import org.matsim.api.core.v01.network.Link -import org.matsim.core.network.NetworkUtils -import org.matsim.core.network.io.MatsimNetworkReader -import org.matsim.core.utils.collections.QuadTree - -import scala.collection.JavaConverters._ -import scala.util.Random - -/** - * @author Dmitry Openkov - */ -object TazToLinkLevelParkingApp extends App with StrictLogging { - - def parseArgs(args: Array[String]) = { - args - .sliding(2, 2) - .toList - .collect { - case Array("--taz-parking", filePath: String) => ("taz-parking", filePath) - case Array("--network", filePath: String) => ("network", filePath) - case Array("--taz-centers", filePath: String) => ("taz-centers", filePath) - case Array("--out", filePath: String) => ("out", filePath) - case arg @ _ => - throw new IllegalArgumentException(arg.mkString(" ")) - } - .toMap - } - - private val argsMap = parseArgs(args) - - if (argsMap.size != 4) { - println( - "Usage: --taz-parking test/input/beamville/parking/taz-parking.csv" + - " --network test/input/beamville/r5/physsim-network.xml" + - " --taz-centers test/input/beamville/taz-centers.csv --out test/input/beamville/parking/link-parking.csv" - ) - System.exit(1) - } - logger.info("args = {}", argsMap) - - private val tazMap = TAZTreeMap.getTazTreeMap(argsMap("taz-centers")) - - private val network = { - val network = NetworkUtils.createNetwork() - new MatsimNetworkReader(network).readFile(argsMap("network")) - network - } - - private val (parkingZones: Map[Id[ParkingZoneId], ParkingZone[TAZ]], _: ZoneSearchTree[TAZ]) = - ParkingZoneFileUtils.fromFile[TAZ](argsMap("taz-parking"), new Random(), None, None) - - private val linkToTaz = LinkLevelOperations.getLinkToTazMapping(network, tazMap) - - logger.info(s"Number of links in the network: ${linkToTaz.size}") - - private val linkQuadTree: QuadTree[Link] = - LinkLevelOperations.getLinkTreeMap(network.getLinks.values().asScala.toSeq) - - private val zoneArrayLink: Map[Id[ParkingZoneId], ParkingZone[Link]] = - ParkingZoneFileUtils.generateLinkParkingOutOfTazParking(parkingZones, linkQuadTree, linkToTaz, tazMap) - - private val zoneSearchTreeLink = zoneArrayLink.values - .groupBy(_.geoId) - .mapValues { zones => - zones - .groupBy(zone => zone.parkingType) - .mapValues(zonesByType => zonesByType.map(_.parkingZoneId).toVector) - } - - logger.info("Generated {} zones", zoneArrayLink.size) - logger.info("with {} parking stalls", zoneArrayLink.map(_._2.stallsAvailable.toLong).sum) - ParkingZoneFileUtils.writeParkingZoneFile(zoneSearchTreeLink, zoneArrayLink, argsMap("out")) - -} diff --git a/src/main/scala/beam/agentsim/infrastructure/power/SitePowerManager.scala b/src/main/scala/beam/agentsim/infrastructure/power/SitePowerManager.scala index 9a965092199..b90b17caf58 100644 --- a/src/main/scala/beam/agentsim/infrastructure/power/SitePowerManager.scala +++ b/src/main/scala/beam/agentsim/infrastructure/power/SitePowerManager.scala @@ -101,7 +101,7 @@ class SitePowerManager( requiredLoad, beamServices, "CNM", - geoIdMaybe = Some(station.zone.geoId.toString) + geoIdMaybe = Some(station.zone.tazId.toString) ) ) } diff --git a/src/main/scala/beam/agentsim/infrastructure/taz/TAZ.scala b/src/main/scala/beam/agentsim/infrastructure/taz/TAZ.scala index d78d0d71e45..5b6a9c2938f 100644 --- a/src/main/scala/beam/agentsim/infrastructure/taz/TAZ.scala +++ b/src/main/scala/beam/agentsim/infrastructure/taz/TAZ.scala @@ -27,6 +27,8 @@ object TAZ { val DefaultTAZ: TAZ = new TAZ(DefaultTAZId, new Coord(), 0) + def isSpecialTazId(tazId: Id[TAZ]): Boolean = tazId == DefaultTAZId || tazId == EmergencyTAZId + /** * performs a concentric disc search from the present location to find TAZs up to the SearchMaxRadius * @param tazQuadTree tree to search diff --git a/src/main/scala/beam/sim/BeamHelper.scala b/src/main/scala/beam/sim/BeamHelper.scala index ffea122dc0f..34583d68dc8 100755 --- a/src/main/scala/beam/sim/BeamHelper.scala +++ b/src/main/scala/beam/sim/BeamHelper.scala @@ -7,7 +7,6 @@ import beam.agentsim.agents.ridehail.{RideHailIterationHistory, RideHailSurgePri import beam.agentsim.agents.vehicles.VehicleCategory.MediumDutyPassenger import beam.agentsim.agents.vehicles._ import beam.agentsim.events.handling.BeamEventsHandling -import beam.agentsim.infrastructure.parking.LinkLevelOperations import beam.agentsim.infrastructure.taz.{H3TAZ, TAZ, TAZTreeMap} import beam.analysis.ActivityLocationPlotter import beam.analysis.plots.{GraphSurgePricing, RideHailRevenueAnalysis} @@ -301,10 +300,6 @@ trait BeamHelper extends LazyLogging { val trainStopQuadTree = GTFSUtils.toQuadTree(GTFSUtils.trainStations(gtfs), new GeoUtilsImpl(beamConfig)) val tazMap = TAZTreeMap.getTazTreeMap(beamConfig.beam.agentsim.taz.filePath) val exchangeGeo = beamConfig.beam.exchange.output.geo.filePath.map(TAZTreeMap.getTazTreeMap) - val linkQuadTree: QuadTree[Link] = - LinkLevelOperations.getLinkTreeMap(networkCoordinator.network.getLinks.values().asScala.toSeq) - val linkIdMapping: Map[Id[Link], Link] = LinkLevelOperations.getLinkIdMapping(networkCoordinator.network) - val linkToTAZMapping: Map[Link, TAZ] = LinkLevelOperations.getLinkToTazMapping(networkCoordinator.network, tazMap) val (freightCarriers, fixedActivitiesDurationsFromFreight) = readFreights(beamConfig, networkCoordinator.transportNetwork.streetLayer, vehicleTypes, outputDirMaybe) @@ -338,9 +333,6 @@ trait BeamHelper extends LazyLogging { trainStopQuadTree, tazMap, exchangeGeo, - linkQuadTree, - linkIdMapping, - linkToTAZMapping, ModeIncentive(beamConfig.beam.agentsim.agents.modeIncentive.filePath), H3TAZ(networkCoordinator.network, tazMap, beamConfig), freightCarriers, diff --git a/src/main/scala/beam/sim/BeamScenario.scala b/src/main/scala/beam/sim/BeamScenario.scala index b24b7b3aec2..80697f6193f 100644 --- a/src/main/scala/beam/sim/BeamScenario.scala +++ b/src/main/scala/beam/sim/BeamScenario.scala @@ -46,9 +46,6 @@ case class BeamScenario( trainStopQuadTree: QuadTree[Stop], tazTreeMap: TAZTreeMap, exchangeGeoMap: Option[TAZTreeMap], - linkQuadTree: QuadTree[Link], - linkIdMapping: Map[Id[Link], Link], - linkToTAZMapping: Map[Link, TAZ], modeIncentives: ModeIncentive, h3taz: H3TAZ, freightCarriers: IndexedSeq[FreightCarrier], diff --git a/src/main/scala/beam/sim/common/GeoUtils.scala b/src/main/scala/beam/sim/common/GeoUtils.scala index ddb56a0e49c..371c8c68988 100755 --- a/src/main/scala/beam/sim/common/GeoUtils.scala +++ b/src/main/scala/beam/sim/common/GeoUtils.scala @@ -238,6 +238,34 @@ object GeoUtils { Math.sqrt(Math.pow(x1 - x2, 2.0) + Math.pow(y1 - y2, 2.0)) } + def isPointWithinCircle(center: Coord, radiusSquared: Double, point: Coord): Boolean = { + val dx = point.getX - center.getX + val dy = point.getY - center.getY + dx * dx + dy * dy <= radiusSquared + } + + /** + * Calculates point of intersection between a circle and a segment that starts at `point` and ends at the circle center + * @param center circle center + * @param radius circle radius + * @param point segment starting point + * @return intersection of the circle and the segment or the circle center if the point == center + */ + def segmentCircleIntersection(center: Coord, radius: Double, point: Coord): Coord = { + val dx = point.getX - center.getX + val dy = point.getY - center.getY + if (dx == 0) { + new Coord(center.getX, center.getY + Math.signum(dy) * radius) + } else { + val m = dy / dx + val m2 = m * m + new Coord( + center.getX + Math.signum(dx) * radius / Math.sqrt(1 + m2), + center.getY + Math.signum(dy) * radius / Math.sqrt(1 + 1 / m2) + ) + } + } + /** * Calculate the Minkowski distance between two coordinates. Provided coordinates need to be in UTM. * diff --git a/src/main/scala/beam/sim/config/BeamConfig.scala b/src/main/scala/beam/sim/config/BeamConfig.scala index c9e3b690637..06bb010677e 100644 --- a/src/main/scala/beam/sim/config/BeamConfig.scala +++ b/src/main/scala/beam/sim/config/BeamConfig.scala @@ -2077,7 +2077,6 @@ object BeamConfig { case class ParkingManager( displayPerformanceTimings: scala.Boolean, - level: java.lang.String, method: java.lang.String, parallel: BeamConfig.Beam.Agentsim.Taz.ParkingManager.Parallel ) @@ -2101,7 +2100,6 @@ object BeamConfig { BeamConfig.Beam.Agentsim.Taz.ParkingManager( displayPerformanceTimings = c.hasPathOrNull("displayPerformanceTimings") && c.getBoolean("displayPerformanceTimings"), - level = if (c.hasPathOrNull("level")) c.getString("level") else "TAZ", method = if (c.hasPathOrNull("method")) c.getString("method") else "DEFAULT", parallel = BeamConfig.Beam.Agentsim.Taz.ParkingManager.Parallel( if (c.hasPathOrNull("parallel")) c.getConfig("parallel") diff --git a/src/main/scala/beam/sim/metrics/BeamStaticMetricsWriter.scala b/src/main/scala/beam/sim/metrics/BeamStaticMetricsWriter.scala index d1ca2001618..3f6e09665de 100644 --- a/src/main/scala/beam/sim/metrics/BeamStaticMetricsWriter.scala +++ b/src/main/scala/beam/sim/metrics/BeamStaticMetricsWriter.scala @@ -93,7 +93,7 @@ object BeamStaticMetricsWriter { val parkingStallCountScalingFactor = beamServices.beamConfig.beam.agentsim.taz.parkingStallCountScalingFactor val (chargingDepots, _) = ParkingZoneFileUtils - .fromFile[TAZ]( + .fromFile( chargingDepotsFilePath, rand, Some(beamScenario.beamConfig), @@ -117,7 +117,7 @@ object BeamStaticMetricsWriter { val rand = new Random(beamScenario.beamConfig.matsim.modules.global.randomSeed) val (publicChargers, _) = ParkingZoneFileUtils - .fromFile[TAZ]( + .fromFile( publicFastChargerFilePath, rand, Some(beamConfig), diff --git a/src/test/scala/beam/agentsim/agents/PersonAndTransitDriverSpec.scala b/src/test/scala/beam/agentsim/agents/PersonAndTransitDriverSpec.scala index 46d18935a89..fbe12b44a71 100644 --- a/src/test/scala/beam/agentsim/agents/PersonAndTransitDriverSpec.scala +++ b/src/test/scala/beam/agentsim/agents/PersonAndTransitDriverSpec.scala @@ -69,7 +69,7 @@ class PersonAndTransitDriverSpec override def outputDirPath: String = TestConfigUtils.testOutputDir - private var parkingNetwork: ParkingNetwork[_] = _ + private var parkingNetwork: ParkingNetwork = _ private var parkingManager: ActorRef = _ private val householdsFactory: HouseholdsFactoryImpl = new HouseholdsFactoryImpl() diff --git a/src/test/scala/beam/agentsim/infrastructure/ChargingNetworkManagerSpec.scala b/src/test/scala/beam/agentsim/infrastructure/ChargingNetworkManagerSpec.scala index 5bcaceb569f..a02a2180065 100644 --- a/src/test/scala/beam/agentsim/infrastructure/ChargingNetworkManagerSpec.scala +++ b/src/test/scala/beam/agentsim/infrastructure/ChargingNetworkManagerSpec.scala @@ -129,7 +129,6 @@ class ChargingNetworkManagerSpec val parkingStall: ParkingStall = ParkingStall( - taz2.tazId, taz2.tazId, parkingZoneId, taz2.coord, diff --git a/src/test/scala/beam/agentsim/infrastructure/ChargingNetworkSpec.scala b/src/test/scala/beam/agentsim/infrastructure/ChargingNetworkSpec.scala index 2dc22f2e6b6..29d3c32ab64 100644 --- a/src/test/scala/beam/agentsim/infrastructure/ChargingNetworkSpec.scala +++ b/src/test/scala/beam/agentsim/infrastructure/ChargingNetworkSpec.scala @@ -98,7 +98,6 @@ class ChargingNetworkSpec ParkingInquiry.init(centerSpaceTime, "work", beamVehicle = Some(vehicle1), triggerId = 73737) val expectedFirstStall = ParkingStall( - Id.create(1, classOf[TAZ]), Id.create(1, classOf[TAZ]), ParkingZone.createId("0"), coordCenterOfUTM, @@ -141,12 +140,11 @@ object ChargingNetworkSpec { geo: GeoUtils, parkingDescription: Iterator[String], boundingBox: Envelope - ): ChargingNetwork[TAZ] = { - ChargingNetwork[TAZ]( + ): ChargingNetwork = { + ChargingNetwork( parkingDescription, tazTreeMap.tazQuadTree, tazTreeMap.idToTAZMapping, - identity[TAZ](_), boundingBox, beamConfig, None, diff --git a/src/test/scala/beam/agentsim/infrastructure/HierarchicalParkingManagerSpec.scala b/src/test/scala/beam/agentsim/infrastructure/HierarchicalParkingManagerSpec.scala index ee1a055045c..749a7b0c11d 100644 --- a/src/test/scala/beam/agentsim/infrastructure/HierarchicalParkingManagerSpec.scala +++ b/src/test/scala/beam/agentsim/infrastructure/HierarchicalParkingManagerSpec.scala @@ -70,9 +70,8 @@ class HierarchicalParkingManagerSpec yMax = 10000000 ) // one TAZ at agent coordinate parkingManager = HierarchicalParkingManager.init( - Map.empty[Id[ParkingZoneId], ParkingZone[Link]], + Map.empty[Id[ParkingZoneId], ParkingZone], tazTreeMap, - HierarchicalParkingManagerSpec.mockLinks(tazTreeMap), geo.distUTMInMeters, 250.0, 8000.0, @@ -91,9 +90,7 @@ class HierarchicalParkingManagerSpec inquiry.destinationUtm.loc.getY + 2000, inquiry.destinationUtm.loc.getY - 2000 ), - new Random(randomSeed), - tazId = TAZ.EmergencyTAZId, - geoId = LinkLevelOperations.EmergencyLinkId + new Random(randomSeed) ) val response = parkingManager.processParkingInquiry(inquiry) @@ -112,9 +109,8 @@ class HierarchicalParkingManagerSpec val tazTreeMap = new TAZTreeMap(new QuadTree[TAZ](0, 0, 0, 0)) val parkingManager = HierarchicalParkingManager.init( - Map.empty[Id[ParkingZoneId], ParkingZone[Link]], + Map.empty[Id[ParkingZoneId], ParkingZone], tazTreeMap, - HierarchicalParkingManagerSpec.mockLinks(tazTreeMap), geo.distUTMInMeters, 250.0, 8000.0, @@ -132,9 +128,7 @@ class HierarchicalParkingManagerSpec inquiry.destinationUtm.loc.getY + 2000, inquiry.destinationUtm.loc.getY - 2000 ), - new Random(randomSeed), - tazId = TAZ.EmergencyTAZId, - geoId = LinkLevelOperations.EmergencyLinkId + new Random(randomSeed) ) val response = parkingManager.processParkingInquiry(inquiry) @@ -164,7 +158,7 @@ class HierarchicalParkingManagerSpec | """.stripMargin.split("\n").toIterator random = new Random(randomSeed) - parking = ParkingZoneFileUtils.fromIterator[Link]( + parking = ParkingZoneFileUtils.fromIterator( oneParkingOption, Some(beamConfig), None, @@ -173,7 +167,6 @@ class HierarchicalParkingManagerSpec parkingManager = HierarchicalParkingManager.init( parking.zones.toMap, tazTreeMap, - HierarchicalParkingManagerSpec.mockLinks(tazTreeMap), geo.distUTMInMeters, 250.0, 8000.0, @@ -189,7 +182,6 @@ class HierarchicalParkingManagerSpec ParkingInquiry.init(centerSpaceTime, "work", triggerId = 734734) val expectedFirstStall = ParkingStall( - Id.create(1, classOf[TAZ]), Id.create(1, classOf[TAZ]), ParkingZone.createId("0"), coordCenterOfUTM, @@ -212,7 +204,7 @@ class HierarchicalParkingManagerSpec val response2 = parkingManager.processParkingInquiry(secondInquiry) response2 match { case Some(ParkingInquiryResponse(stall, responseId, secondInquiry.triggerId)) - if stall.geoId == LinkLevelOperations.EmergencyLinkId && responseId == secondInquiry.requestId => + if stall.tazId == TAZ.EmergencyTAZId && responseId == secondInquiry.requestId => case _ => assert(response2.isDefined, "no response") } } @@ -238,7 +230,7 @@ class HierarchicalParkingManagerSpec """.stripMargin.split("\n").toIterator random = new Random(randomSeed) parking = ParkingZoneFileUtils - .fromIterator[Link]( + .fromIterator( oneParkingOption, Some(beamConfig), None, @@ -247,7 +239,6 @@ class HierarchicalParkingManagerSpec parkingManager = HierarchicalParkingManager.init( parking.zones.toMap, tazTreeMap, - HierarchicalParkingManagerSpec.mockLinks(tazTreeMap), geo.distUTMInMeters, 250.0, 8000.0, @@ -263,7 +254,6 @@ class HierarchicalParkingManagerSpec val expectedTAZId = Id.create(1, classOf[TAZ]) val expectedStall = ParkingStall( - expectedTAZId, expectedTAZId, ParkingZone.createId("0"), coordCenterOfUTM, @@ -325,7 +315,7 @@ class HierarchicalParkingManagerSpec split = ZonalParkingManagerSpec.randomSplitOfMaxStalls(numStalls, 4, random1) parkingConfiguration: Iterator[String] = ZonalParkingManagerSpec.makeParkingConfiguration(split) random = new Random(randomSeed) - parking = ParkingZoneFileUtils.fromIterator[Link]( + parking = ParkingZoneFileUtils.fromIterator( parkingConfiguration, Some(beamConfig), None, @@ -334,7 +324,6 @@ class HierarchicalParkingManagerSpec parkingManager = HierarchicalParkingManager.init( parking.zones.toMap, tazTreeMap, - HierarchicalParkingManagerSpec.mockLinks(tazTreeMap), geo.distUTMInMeters, 250.0, 8000.0, @@ -351,7 +340,7 @@ class HierarchicalParkingManagerSpec response1 = parkingManager.processParkingInquiry(req) counted = response1 match { case Some(res @ ParkingInquiryResponse(_, _, req.triggerId)) => - if (res.stall.geoId != LinkLevelOperations.EmergencyLinkId) 1 else 0 + if (res.stall.tazId != TAZ.EmergencyTAZId) 1 else 0 case _ => assert(response1.isDefined, "no response") 0 @@ -373,8 +362,8 @@ class HierarchicalParkingManagerSpec val scenario = loadScenario(beamConfig) val stalls = InfrastructureUtils - .loadStalls[Link]( - "test/input/beamville/parking/link-parking.csv", + .loadStalls( + "test/input/beamville/parking/taz-parking.csv", IndexedSeq.empty, null, //it is required only in case of failures 1.0, @@ -388,7 +377,6 @@ class HierarchicalParkingManagerSpec val zpm = HierarchicalParkingManager.init( stalls, scenario.tazTreeMap, - scenario.linkToTAZMapping, geo.distUTMInMeters, 250.0, 8000.0, @@ -422,7 +410,7 @@ class HierarchicalParkingManagerSpec } private def assertParkingResponse( - spm: ParkingNetwork[_], + spm: ParkingNetwork, coord: Coord, tazId: String, reservedFor: ReservedFor @@ -446,16 +434,6 @@ class HierarchicalParkingManagerSpec object HierarchicalParkingManagerSpec { - private def mockLinks(tazTreeMap: TAZTreeMap): Map[Link, TAZ] = { - tazTreeMap.getTAZs - .flatMap { taz => - Array.fill(3)(taz) - } - .zipWithIndex - .map { case (taz, i) => mockLink(taz.coord, i, 100) -> taz } - .toMap - } - def mockLink(coord: Coord, id: Long, len: Double): Link = { val link = mock(classOf[Link]) when(link.getCoord).thenReturn(coord) diff --git a/src/test/scala/beam/agentsim/infrastructure/HierarchicalParkingManagerUtilSpec.scala b/src/test/scala/beam/agentsim/infrastructure/HierarchicalParkingManagerUtilSpec.scala index 5209dd515ef..c3f278371c4 100644 --- a/src/test/scala/beam/agentsim/infrastructure/HierarchicalParkingManagerUtilSpec.scala +++ b/src/test/scala/beam/agentsim/infrastructure/HierarchicalParkingManagerUtilSpec.scala @@ -4,18 +4,12 @@ import beam.agentsim.infrastructure.charging.ChargingPointType.CustomChargingPoi import beam.agentsim.infrastructure.charging.ElectricCurrentType.DC import beam.agentsim.infrastructure.parking.ParkingType.Residential import beam.agentsim.infrastructure.parking.ParkingZoneFileUtilsSpec.PositiveTestData -import beam.agentsim.infrastructure.parking.{LinkLevelOperations, ParkingZone, ParkingZoneFileUtils, ParkingZoneId} -import beam.agentsim.infrastructure.taz.{TAZ, TAZTreeMap} +import beam.agentsim.infrastructure.parking.{ParkingZone, ParkingZoneFileUtils, ParkingZoneId} import org.matsim.api.core.v01.Id -import org.matsim.api.core.v01.network.Link import org.scalatest.LoneElement.convertToCollectionLoneElementWrapper import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec -import scala.collection.immutable.HashMap -import scala.jdk.CollectionConverters.collectionAsScalaIterableConverter -import scala.util.Random - /** * @author Dmitry Openkov */ @@ -25,35 +19,27 @@ class HierarchicalParkingManagerUtilSpec extends AnyWordSpec with Matchers { "produce correct zones" in new PositiveTestData { val ParkingZoneFileUtils.ParkingLoadingAccumulator(linkZones, _, _, _) = - ParkingZoneFileUtils.fromIterator[Link](linkLevelData, None, None) - - val linkToTazMapping: Map[Id[Link], Id[TAZ]] = HashMap( - Id.createLinkId(49577) -> Id.create(100026, classOf[TAZ]), - Id.createLinkId(83658) -> Id.create(100026, classOf[TAZ]), - Id.createLinkId(83661) -> Id.create(100026, classOf[TAZ]), - Id.createLinkId(83663) -> Id.create(100100, classOf[TAZ]), - Id.createLinkId(83664) -> Id.create(100100, classOf[TAZ]) - ) + ParkingZoneFileUtils.fromIterator(parkingWithLocation, None, None) private val (tazZones, linkZoneToTazZoneMap) = - HierarchicalParkingManager.convertToTazParkingZones(linkZones.toMap, linkToTazMapping) + HierarchicalParkingManager.convertToTazParkingZones(linkZones.toMap) - println(tazZones.mkString("Array(", ", ", ")")) + println(tazZones.values.mkString("Array(", ", ", ")")) println(linkZoneToTazZoneMap.mkString("Array(", ", ", ")")) tazZones.size should be(9) - val joinZone: Option[ParkingZone[TAZ]] = tazZones.values.find { zone => - zone.geoId.toString == "100026" && zone.parkingType == Residential && zone.chargingPointType.contains( + val joinZone: Option[ParkingZone] = tazZones.values.find { zone => + zone.tazId.toString == "100026" && zone.parkingType == Residential && zone.chargingPointType.contains( CustomChargingPoint("dcfast", 50.0, DC) ) } joinZone shouldBe defined joinZone.get.maxStalls should be(1100) - tazZones.count(_._2.geoId.toString == "100100") should be(2) + tazZones.count(_._2.tazId.toString == "100100") should be(2) val zoneOfTaz100100 = tazZones.values .filter(zone => - zone.geoId.toString == "100100" + zone.tazId.toString == "100100" && zone.chargingPointType.exists(_.toString.startsWith("ultrafast")) ) .loneElement @@ -69,38 +55,9 @@ class HierarchicalParkingManagerUtilSpec extends AnyWordSpec with Matchers { linkZoneToTazZoneMap.groupBy { case (_, tazZoneId) => tazZoneId }.values.map(_.keySet).toIndexedSeq val (singles, collapsed) = groupedByTazZone.partition(_.size == 1) singles should have size 7 - collapsed.map(_.map(_.toString)) should contain theSameElementsAs (Seq(Set("4", "7"), Set("10", "11"))) + collapsed.map(_.map(_.toString)) should contain theSameElementsAs Seq(Set("4", "7"), Set("10", "11")) } } } - "creates taz link quad tree mapping" should { - "correct quad tree" in { - val network = - NetworkUtilsExtensions.readNetwork("test/test-resources/beam/physsim/beamville-network-output.xml") - val totalNumberOfLinks = network.getLinks.size() - val tazTreeMap = TAZTreeMap.fromCsv("test/input/beamville/taz-centers.csv") - val totalNumberOfTAZes = tazTreeMap.tazQuadTree.size() - - val linkToTAZMapping: Map[Link, TAZ] = LinkLevelOperations.getLinkToTazMapping(network, tazTreeMap) - linkToTAZMapping.size should be(totalNumberOfLinks) - linkToTAZMapping.values.toSet.size should be(totalNumberOfTAZes) - - val tazToLinkQuads = HierarchicalParkingManager.createTazLinkQuadTreeMapping(linkToTAZMapping) - tazToLinkQuads.values.map(_.size()).sum should be(totalNumberOfLinks) - - //get certain TAZ links and validate that it contains the right ones. - val myTazId: Id[TAZ] = Id.create(1, classOf[TAZ]) - val myZonesTree = tazToLinkQuads(myTazId) - myZonesTree.values().size() should be(130) - myZonesTree.values().asScala.map(_.getId.toString).toList should contain allElementsOf List( - "2", - "3", - "6", - "7", - "322", - "323" - ) - } - } } } diff --git a/src/test/scala/beam/agentsim/infrastructure/ParallelParkingManagerSpec.scala b/src/test/scala/beam/agentsim/infrastructure/ParallelParkingManagerSpec.scala index aeafa30a24e..9701c3c5918 100644 --- a/src/test/scala/beam/agentsim/infrastructure/ParallelParkingManagerSpec.scala +++ b/src/test/scala/beam/agentsim/infrastructure/ParallelParkingManagerSpec.scala @@ -67,7 +67,7 @@ class ParallelParkingManagerSpec yMax = 10000000 ) // one TAZ at agent coordinate parkingManager = ParallelParkingManager.init( - Map.empty[Id[ParkingZoneId], ParkingZone[TAZ]], + Map.empty[Id[ParkingZoneId], ParkingZone], beamConfig, tazTreeMap, geo.distUTMInMeters, @@ -85,9 +85,7 @@ class ParallelParkingManagerSpec inquiry.destinationUtm.loc.getY + 2000, inquiry.destinationUtm.loc.getY - 2000 ), - new Random(randomSeed), - tazId = TAZ.EmergencyTAZId, - geoId = TAZ.EmergencyTAZId + new Random(randomSeed) ) val response = parkingManager.processParkingInquiry(inquiry) @@ -106,7 +104,7 @@ class ParallelParkingManagerSpec val tazTreeMap = new TAZTreeMap(new QuadTree[TAZ](0, 0, 0, 0)) val parkingManager = ParallelParkingManager.init( - Map.empty[Id[ParkingZoneId], ParkingZone[TAZ]], + Map.empty[Id[ParkingZoneId], ParkingZone], beamConfig, tazTreeMap, geo.distUTMInMeters, @@ -123,9 +121,7 @@ class ParallelParkingManagerSpec inquiry.destinationUtm.loc.getY + 2000, inquiry.destinationUtm.loc.getY - 2000 ), - random = new Random(randomSeed.toLong), - tazId = TAZ.EmergencyTAZId, - geoId = TAZ.EmergencyTAZId + random = new Random(randomSeed.toLong) ) val response = parkingManager.processParkingInquiry(inquiry) @@ -155,7 +151,7 @@ class ParallelParkingManagerSpec | """.stripMargin.split("\n").toIterator random = new Random(randomSeed) - parking = ParkingZoneFileUtils.fromIterator[TAZ](oneParkingOption, Some(beamConfig), None, random) + parking = ParkingZoneFileUtils.fromIterator(oneParkingOption, Some(beamConfig), None, random) parkingManager = ParallelParkingManager.init( parking.zones.toMap, beamConfig, @@ -171,7 +167,6 @@ class ParallelParkingManagerSpec val firstInquiry = ParkingInquiry.init(centerSpaceTime, "work", triggerId = 9902) val expectedFirstStall = ParkingStall( - Id.create(1, classOf[TAZ]), Id.create(1, classOf[TAZ]), ParkingZone.createId("a"), coordCenterOfUTM, @@ -193,7 +188,7 @@ class ParallelParkingManagerSpec val response2 = parkingManager.processParkingInquiry(secondInquiry) response2 match { case Some(ParkingInquiryResponse(stall, responseId, triggerId)) - if stall.geoId == TAZ.EmergencyTAZId + if stall.tazId == TAZ.EmergencyTAZId && responseId == secondInquiry.requestId && triggerId == secondInquiry.triggerId => case _ => assert(response2.isDefined, "no response") } @@ -219,7 +214,7 @@ class ParallelParkingManagerSpec | """.stripMargin.split("\n").toIterator random = new Random(randomSeed) - parking = ParkingZoneFileUtils.fromIterator[TAZ](oneParkingOption, Some(beamConfig), None, random) + parking = ParkingZoneFileUtils.fromIterator(oneParkingOption, Some(beamConfig), None, random) parkingManager = ParallelParkingManager.init( parking.zones.toMap, beamConfig, @@ -237,7 +232,6 @@ class ParallelParkingManagerSpec val expectedTAZId = Id.create(1, classOf[TAZ]) val expectedStall = ParkingStall( - expectedTAZId, expectedTAZId, ParkingZone.createId("a"), coordCenterOfUTM, @@ -299,7 +293,7 @@ class ParallelParkingManagerSpec split = ZonalParkingManagerSpec.randomSplitOfMaxStalls(numStalls, 4, random1) parkingConfiguration: Iterator[String] = ZonalParkingManagerSpec.makeParkingConfiguration(split) random = new Random(randomSeed) - parking = ParkingZoneFileUtils.fromIterator[TAZ](parkingConfiguration, Some(beamConfig), None, random) + parking = ParkingZoneFileUtils.fromIterator(parkingConfiguration, Some(beamConfig), None, random) parkingManager = ParallelParkingManager.init( parking.zones.toMap, beamConfig, @@ -317,7 +311,7 @@ class ParallelParkingManagerSpec response1 = parkingManager.processParkingInquiry(req) counted = response1 match { case Some(res @ ParkingInquiryResponse(_, _, _)) => - if (res.stall.geoId != TAZ.EmergencyTAZId) 1 else 0 + if (res.stall.tazId != TAZ.EmergencyTAZId) 1 else 0 case _ => assert(response1.isDefined, "no response") 0 @@ -337,7 +331,7 @@ class ParallelParkingManagerSpec describe("ParallelParkingManager with loaded common data") { it("should return the correct stall") { val tazMap = taz.TAZTreeMap.fromCsv("test/input/beamville/taz-centers.csv") - val stalls = InfrastructureUtils.loadStalls[TAZ]( + val stalls = InfrastructureUtils.loadStalls( "test/input/beamville/parking/taz-parking.csv", IndexedSeq.empty, tazMap.tazQuadTree, @@ -347,7 +341,7 @@ class ParallelParkingManagerSpec beamConfig, None ) - val parkingZones = InfrastructureUtils.loadParkingStalls[TAZ](stalls) + val parkingZones = InfrastructureUtils.loadParkingStalls(stalls) val zpm = ParallelParkingManager.init( parkingZones, beamConfig, @@ -391,7 +385,7 @@ class ParallelParkingManagerSpec } private def assertParkingResponse( - spm: ParkingNetwork[_], + spm: ParkingNetwork, coord: Coord, tazId: String, parkingZoneId: Id[ParkingZoneId], @@ -404,7 +398,6 @@ class ParallelParkingManagerSpec val tazId1 = Id.create(tazId, classOf[TAZ]) val expectedStall = ParkingStall( - tazId1, tazId1, parkingZoneId, coord, diff --git a/src/test/scala/beam/agentsim/infrastructure/ParallelParkingManagerUtilSpec.scala b/src/test/scala/beam/agentsim/infrastructure/ParallelParkingManagerUtilSpec.scala index 09c5316a9d7..7a422e6f66b 100644 --- a/src/test/scala/beam/agentsim/infrastructure/ParallelParkingManagerUtilSpec.scala +++ b/src/test/scala/beam/agentsim/infrastructure/ParallelParkingManagerUtilSpec.scala @@ -71,7 +71,7 @@ class ParallelParkingManagerUtilSpec extends AnyWordSpecLike with Matchers { "Handle empty tazTreeMap" in { val treeMap = new TAZTreeMap(new QuadTree[TAZ](0, 0, 0, 0)) - val parkingZones = Map.empty[Id[ParkingZoneId], ParkingZone[TAZ]] + val parkingZones = Map.empty[Id[ParkingZoneId], ParkingZone] val clusters: Vector[ParallelParkingManager.ParkingCluster] = ParallelParkingManager.createClusters(treeMap, parkingZones, 2, 2) diff --git a/src/test/scala/beam/agentsim/infrastructure/ZonalParkingManagerSpec.scala b/src/test/scala/beam/agentsim/infrastructure/ZonalParkingManagerSpec.scala index 28d899d2317..8dfb98fdc98 100644 --- a/src/test/scala/beam/agentsim/infrastructure/ZonalParkingManagerSpec.scala +++ b/src/test/scala/beam/agentsim/infrastructure/ZonalParkingManagerSpec.scala @@ -93,8 +93,7 @@ class ZonalParkingManagerSpec inquiry.destinationUtm.loc.getY + 2000, inquiry.destinationUtm.loc.getY - 2000 ), - new Random(randomSeed), - geoId = TAZ.EmergencyTAZId + new Random(randomSeed) ) val response = zonalParkingManager.processParkingInquiry(inquiry) @@ -144,7 +143,6 @@ class ZonalParkingManagerSpec ParkingInquiry.init(centerSpaceTime, "work", triggerId = 3234324) val expectedFirstStall = ParkingStall( - Id.create(1, classOf[TAZ]), Id.create(1, classOf[TAZ]), ParkingZone.createId("0"), coordCenterOfUTM, @@ -168,7 +166,7 @@ class ZonalParkingManagerSpec zonalParkingManager.processParkingInquiry(secondInquiry) assert(response2.isDefined, "no response") assert( - stall.geoId == TAZ.EmergencyTAZId && responseId == secondInquiry.requestId + stall.tazId == TAZ.EmergencyTAZId && responseId == secondInquiry.requestId && triggerId == secondInquiry.triggerId, "something is wildly broken" ) @@ -210,7 +208,6 @@ class ZonalParkingManagerSpec val expectedTAZId = Id.create(1, classOf[TAZ]) val expectedStall = ParkingStall( - expectedTAZId, expectedTAZId, ParkingZone.createId("0"), coordCenterOfUTM, @@ -292,7 +289,7 @@ class ZonalParkingManagerSpec response1 = zonalParkingManager.processParkingInquiry(req) counted = response1 match { case Some(res @ ParkingInquiryResponse(_, _, _)) => - if (res.stall.geoId != TAZ.EmergencyTAZId) 1 else 0 + if (res.stall.tazId != TAZ.EmergencyTAZId) 1 else 0 case _ => assert(response1.isDefined, "no response") 0 @@ -321,7 +318,6 @@ class ZonalParkingManagerSpec parkingDescription, tazMap.tazQuadTree, tazMap.idToTAZMapping, - identity[TAZ](_), boundingBox, geo.distUTMInMeters(_, _), minSearchRadius, @@ -381,7 +377,6 @@ class ZonalParkingManagerSpec parkingDescription, tazMap.tazQuadTree, tazMap.idToTAZMapping, - identity[TAZ](_), boundingBox, geo.distUTMInMeters(_, _), minSearchRadius, @@ -409,7 +404,7 @@ class ZonalParkingManagerSpec val sharedFleet1 = VehicleManager.createOrGetReservedFor("shared-fleet-1", VehicleManager.TypeEnum.Shared) val sharedFleet2 = VehicleManager.createOrGetReservedFor("shared-fleet-2", VehicleManager.TypeEnum.Shared) val tazMap = taz.TAZTreeMap.fromCsv("test/input/beamville/taz-centers.csv") - val stalls = InfrastructureUtils.loadStalls[TAZ]( + val stalls = InfrastructureUtils.loadStalls( "test/test-resources/beam/agentsim/infrastructure/taz-parking.csv", IndexedSeq( ( @@ -431,11 +426,10 @@ class ZonalParkingManagerSpec None ) val parkingZones = InfrastructureUtils.loadParkingStalls(stalls) - val zonesMap = ZonalParkingManager[TAZ]( + val zonesMap = ZonalParkingManager( parkingZones, tazMap.tazQuadTree, tazMap.idToTAZMapping, - identity[TAZ](_), geo.distUTMInMeters(_, _), boundingBox, beamConfig.beam.agentsim.agents.parking.minSearchRadius, @@ -473,7 +467,7 @@ class ZonalParkingManagerSpec } private def assertVehicleManager( - zpm: ParkingNetwork[_], + zpm: ParkingNetwork, coord: Coord, reservedFor: ReservedFor, vehicleManagerToAssert: Seq[ReservedFor] @@ -493,7 +487,7 @@ class ZonalParkingManagerSpec } private def assertParkingResponse( - zpm: ParkingNetwork[_], + zpm: ParkingNetwork, spaceTime: SpaceTime, tazId: String, parkingZoneId: Id[ParkingZoneId], @@ -516,7 +510,6 @@ class ZonalParkingManagerSpec val costInDollars = if (pricingModel.isInstanceOf[FlatFee]) pricingModel.costInDollars else 0.0 val expectedStall = ParkingStall( - tazId1, tazId1, parkingZoneId, spaceTime.loc, @@ -546,14 +539,13 @@ object ZonalParkingManagerSpec { parkingDescription: Iterator[String], boundingBox: Envelope, seed: Int - ): ZonalParkingManager[TAZ] = { + ): ZonalParkingManager = { val minSearchRadius = 1000.0 val maxSearchRadius = 16093.4 // meters, aka 10 miles ZonalParkingManager( parkingDescription, tazTreeMap.tazQuadTree, tazTreeMap.idToTAZMapping, - identity[TAZ](_), boundingBox, geo.distUTMInMeters(_, _), minSearchRadius, @@ -628,13 +620,13 @@ object ZonalParkingManagerSpec { treeMap: TAZTreeMap, zones: List[Int], reservedFor: ReservedFor - ): Map[Id[ParkingZoneId], ParkingZone[TAZ]] = { + ): Map[Id[ParkingZoneId], ParkingZone] = { val result = treeMap.getTAZs .zip(zones) - .foldLeft(Map.empty[Id[ParkingZoneId], ParkingZone[TAZ]]) { case (acc, (taz, numZones)) => + .foldLeft(Map.empty[Id[ParkingZoneId], ParkingZone]) { case (acc, (taz, numZones)) => val parkingZones = (0 until numZones).map { i => val zone = ParkingZone - .init[TAZ]( + .init( None, taz.tazId, ParkingType.Workplace, diff --git a/src/test/scala/beam/agentsim/infrastructure/parking/ParkingZoneFileUtilsSpec.scala b/src/test/scala/beam/agentsim/infrastructure/parking/ParkingZoneFileUtilsSpec.scala index 59588d55827..2dcd4a0c555 100644 --- a/src/test/scala/beam/agentsim/infrastructure/parking/ParkingZoneFileUtilsSpec.scala +++ b/src/test/scala/beam/agentsim/infrastructure/parking/ParkingZoneFileUtilsSpec.scala @@ -2,14 +2,10 @@ package beam.agentsim.infrastructure.parking import beam.agentsim.agents.vehicles.VehicleCategory.{Car, LightDutyTruck, MediumDutyPassenger} import beam.agentsim.agents.vehicles.{VehicleCategory, VehicleManager} -import beam.agentsim.infrastructure.HierarchicalParkingManager import beam.agentsim.infrastructure.charging.ChargingPointType -import beam.agentsim.infrastructure.parking.ParkingType.{Public, Residential, Workplace} import beam.agentsim.infrastructure.parking.ParkingZoneFileUtilsSpec.PositiveTestData -import beam.agentsim.infrastructure.parking.ParkingZoneSearch.ZoneSearchTree import beam.agentsim.infrastructure.taz.TAZ import org.matsim.api.core.v01.Id -import org.matsim.api.core.v01.network.Link import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec @@ -22,7 +18,7 @@ class ParkingZoneFileUtilsSpec extends AnyWordSpec with Matchers { "a row contains all valid entries" should { "construct a ParkingZone collection and random lookup tree" in new ParkingZoneFileUtilsSpec.PositiveTestData { val ParkingZoneFileUtils.ParkingLoadingAccumulator(collection, lookupTree, totalRows, failedRows) = - ParkingZoneFileUtils.fromIterator[TAZ](validRow, None, None) + ParkingZoneFileUtils.fromIterator(validRow, None, None) totalRows should equal(1) failedRows should equal(0) lookupTree.get(Id.create("1", classOf[TAZ])) match { @@ -38,7 +34,7 @@ class ParkingZoneFileUtilsSpec extends AnyWordSpec with Matchers { // extract parking zone based on discovered zone id val foundParkingZoneId: Id[ParkingZoneId] = listOfParkingZones.head - val parkingZone: ParkingZone[TAZ] = collection(foundParkingZoneId) + val parkingZone: ParkingZone = collection(foundParkingZoneId) // confirm parking zone has correct attributes parkingZone.parkingZoneId should equal(foundParkingZoneId) @@ -70,8 +66,8 @@ class ParkingZoneFileUtilsSpec extends AnyWordSpec with Matchers { } "time restriction" should { "be parsed" in new PositiveTestData { - val result: ParkingZoneFileUtils.ParkingLoadingAccumulator[TAZ] = - ParkingZoneFileUtils.fromIterator[TAZ](timeRestrictionData, None, None) + val result: ParkingZoneFileUtils.ParkingLoadingAccumulator = + ParkingZoneFileUtils.fromIterator(timeRestrictionData, None, None) result.failedRows should be(0) result.totalRows should be(2) result.zones(Id.create("parkingZone1", classOf[ParkingZoneId])).timeRestrictions should be( @@ -94,7 +90,7 @@ class ParkingZoneFileUtilsSpec extends AnyWordSpec with Matchers { "negative tests" when { "parking type doesn't exist" should { "have one failed row" in new ParkingZoneFileUtilsSpec.NegativeTestData { - val result: ParkingZoneFileUtils.ParkingLoadingAccumulator[TAZ] = + val result: ParkingZoneFileUtils.ParkingLoadingAccumulator = ParkingZoneFileUtils.fromIterator(badParkingType, None, None) result.failedRows should equal(1) } @@ -104,7 +100,7 @@ class ParkingZoneFileUtilsSpec extends AnyWordSpec with Matchers { } "pricing model doesn't exist" should { "have one failed row" in new ParkingZoneFileUtilsSpec.NegativeTestData { - val result: ParkingZoneFileUtils.ParkingLoadingAccumulator[TAZ] = + val result: ParkingZoneFileUtils.ParkingLoadingAccumulator = ParkingZoneFileUtils.fromIterator(badPricingModel, None, None) result.failedRows should equal(1) } @@ -114,7 +110,7 @@ class ParkingZoneFileUtilsSpec extends AnyWordSpec with Matchers { } "charging type doesn't exist" ignore { "have one failed row" in new ParkingZoneFileUtilsSpec.NegativeTestData { - val result: ParkingZoneFileUtils.ParkingLoadingAccumulator[TAZ] = + val result: ParkingZoneFileUtils.ParkingLoadingAccumulator = ParkingZoneFileUtils.fromIterator(badChargingType, None, None) result.failedRows should equal(1) } @@ -124,7 +120,7 @@ class ParkingZoneFileUtilsSpec extends AnyWordSpec with Matchers { } "non-numeric number of stalls" should { "have one failed row" in new ParkingZoneFileUtilsSpec.NegativeTestData { - val result: ParkingZoneFileUtils.ParkingLoadingAccumulator[TAZ] = + val result: ParkingZoneFileUtils.ParkingLoadingAccumulator = ParkingZoneFileUtils.fromIterator(badNumStalls, None, None) result.failedRows should equal(1) } @@ -134,7 +130,7 @@ class ParkingZoneFileUtilsSpec extends AnyWordSpec with Matchers { } "invalid (negative) number of stalls" should { "have one failed row" in new ParkingZoneFileUtilsSpec.NegativeTestData { - val result: ParkingZoneFileUtils.ParkingLoadingAccumulator[TAZ] = + val result: ParkingZoneFileUtils.ParkingLoadingAccumulator = ParkingZoneFileUtils.fromIterator(invalidNumStalls, None, None) result.failedRows should equal(1) } @@ -144,7 +140,7 @@ class ParkingZoneFileUtilsSpec extends AnyWordSpec with Matchers { } "non-numeric fee in cents" should { "have one failed row" in new ParkingZoneFileUtilsSpec.NegativeTestData { - val result: ParkingZoneFileUtils.ParkingLoadingAccumulator[TAZ] = + val result: ParkingZoneFileUtils.ParkingLoadingAccumulator = ParkingZoneFileUtils.fromIterator(badFeeInCents, None, None) result.failedRows should equal(1) } @@ -154,47 +150,6 @@ class ParkingZoneFileUtilsSpec extends AnyWordSpec with Matchers { } } } - "creates zone search tree" should { - "produce correct tree" in new PositiveTestData { - val ParkingZoneFileUtils.ParkingLoadingAccumulator(zones, lookupTree, _, _) = - ParkingZoneFileUtils.fromIterator[Link](linkLevelData, None, None) - val tree: ZoneSearchTree[Link] = ParkingZoneFileUtils.createZoneSearchTree(zones.values.toSeq) - tree should equal(lookupTree) - } - "produce correct tree for bigger data" in new PositiveTestData { - val (zones, lookupTree) = - ParkingZoneFileUtils - .fromFile[Link]( - "test/input/sf-light/link-parking.csv.gz", - new Random(42), - None, - None, - 0.13 - ) - val tree: ZoneSearchTree[Link] = ParkingZoneFileUtils.createZoneSearchTree(zones.values.toSeq) - tree should equal(lookupTree) - } - } - - "creates a zone search tree" should { - "produce the right result" in { - val (parkingZones, _) = - ParkingZoneFileUtils - .fromFile[Link]( - "test/test-resources/beam/agentsim/infrastructure/taz-parking-similar-zones.csv", - new Random(777934L), - None, - None - ) - parkingZones should have size 3648 - val zoneSearchTree = ParkingZoneFileUtils.createZoneSearchTree(parkingZones.values.toSeq) - val subTree = zoneSearchTree(Id.create("205", classOf[Link])) - subTree.values.map(_.length).sum should be(20) - subTree(Public) should have length 12 - subTree(Workplace) should have length 4 - subTree(Residential) should have length 4 - } - } "Time restriction parser" when { "parses time restriction" should { @@ -229,20 +184,19 @@ object ParkingZoneFileUtilsSpec { |1,Residential,,,$testNumStalls,$testFeeInCents, """.stripMargin.split("\n").toIterator - val linkLevelData: Iterator[String] = - """taz,parkingZoneId,parkingType,pricingModel,chargingPointType,numStalls,feeInCents,reservedFor - |49577,1,Residential,FlatFee,level1(2.3|AC),10,0.0, - |49577,2,Public,Block,level2(7.2|AC),10,0.0, - |49577,3,Workplace,FlatFee,dcfast(50.0|DC),10,0.0, - |83658,4,Residential,Block,dcfast(50.0|DC),100,0.0, - |83658,5,Residential,FlatFee,NoCharger,100,0.0, - |83658,6,Workplace,FlatFee,ultrafast(250.0|DC),100,0.0, - |83661,7,Residential,Block,dcfast(50.0|DC),1000,0.0, - |83661,8,Public,FlatFee,level2(7.2|AC),1000,0.0, - |83663,9,Workplace,FlatFee,level2(7.2|AC),10000,0.0, - |83663,10,Workplace,FlatFee,ultrafast(250.0|DC),10000,0.0, - |83664,11,Workplace,FlatFee,ultrafast(250.0|DC),10000,0.0, - | + val parkingWithLocation: Iterator[String] = + """taz,parkingType,pricingModel,chargingPointType,numStalls,feeInCents,reservedFor,timeRestrictions,parkingZoneId,locationX,locationY + |100026,Public,FlatFee,level2(7.2|AC),1000,0.0,default(Any),,8,552641.0259207832,4182791.3318920964 + |100026,Public,Block,level2(7.2|AC),10,0.0,default(Any),,2,552628.1558583267,4182794.311948398 + |100026,Residential,Block,dcfast(50.0|DC),100,0.0,default(Any),,4,552683.6140483634,4182803.3378544813 + |100026,Residential,FlatFee,NoCharger,100,0.0,default(Any),,5,552683.6140483634,4182803.3378544813 + |100026,Residential,FlatFee,level1(2.3|AC),10,0.0,default(Any),,1,552628.1558583267,4182794.311948398 + |100026,Residential,Block,dcfast(50.0|DC),1000,0.0,default(Any),,7,552641.0259207832,4182791.3318920964 + |100026,Workplace,FlatFee,ultrafast(250.0|DC),100,0.0,default(Any),,6,552683.6140483634,4182803.3378544813 + |100026,Workplace,FlatFee,dcfast(50.0|DC),10,0.0,default(Any),,3,552628.1558583267,4182794.311948398 + |100100,Workplace,FlatFee,ultrafast(250.0|DC),10000,0.0,default(Any),,11,549303.5066888432,4180190.870930109 + |100100,Workplace,FlatFee,level2(7.2|AC),10000,0.0,default(Any),,9,549199.9541597087,4180090.2839715164 + |100100,Workplace,FlatFee,ultrafast(250.0|DC),10000,0.0,default(Any),,10,549199.9541597087,4180090.2839715164 """.stripMargin.split("\n").toIterator val timeRestrictionData: Iterator[String] = diff --git a/src/test/scala/beam/agentsim/infrastructure/power/PowerControllerSpec.scala b/src/test/scala/beam/agentsim/infrastructure/power/PowerControllerSpec.scala index 2f2199c4fd7..0d3a4735a80 100644 --- a/src/test/scala/beam/agentsim/infrastructure/power/PowerControllerSpec.scala +++ b/src/test/scala/beam/agentsim/infrastructure/power/PowerControllerSpec.scala @@ -48,7 +48,7 @@ class PowerControllerSpec extends AnyWordSpecLike with Matchers with BeforeAndAf val beamFederateMock: BeamFederate = mock(classOf[BeamFederate]) val tazFromBeamville: TAZ = new TAZ(Id.create("1", classOf[TAZ]), new Coord(167141.3, 1112.351), 4840000) - val dummyChargingZone: ParkingZone[TAZ] = ParkingZone.init( + val dummyChargingZone: ParkingZone = ParkingZone.init( None, tazFromBeamville.tazId, ParkingType.Public, @@ -59,14 +59,14 @@ class PowerControllerSpec extends AnyWordSpecLike with Matchers with BeforeAndAf ) val chargingZones = Map(dummyChargingZone.parkingZoneId -> dummyChargingZone) - val chargingNetwork: ChargingNetwork[_] = mock(classOf[ChargingNetwork[_]]) + val chargingNetwork: ChargingNetwork = mock(classOf[ChargingNetwork]) - val rideHailNetwork: ChargingNetwork[_] = mock(classOf[ChargingNetwork[_]]) + val rideHailNetwork: ChargingNetwork = mock(classOf[ChargingNetwork]) val dummyChargingStation: ChargingStation = ChargingStation(dummyChargingZone) val dummyPhysicalBounds = Map( - "tazId" -> dummyChargingZone.geoId.toString, + "tazId" -> dummyChargingZone.tazId.toString, "power_limit_lower" -> 5678.90, "power_limit_upper" -> 5678.90, "lmp_with_control_signal" -> 0.0 diff --git a/src/test/scala/beam/agentsim/infrastructure/power/SitePowerManagerSpec.scala b/src/test/scala/beam/agentsim/infrastructure/power/SitePowerManagerSpec.scala index 4e646e133b1..5b2654465ee 100644 --- a/src/test/scala/beam/agentsim/infrastructure/power/SitePowerManagerSpec.scala +++ b/src/test/scala/beam/agentsim/infrastructure/power/SitePowerManagerSpec.scala @@ -99,7 +99,7 @@ class SitePowerManagerSpec val taz: TAZ = tazMap.getTAZs.head - val dummyChargingZone: ParkingZone[TAZ] = ParkingZone.init( + val dummyChargingZone: ParkingZone = ParkingZone.init( None, taz.tazId, ParkingType.Workplace, @@ -110,7 +110,7 @@ class SitePowerManagerSpec ) private val vehiclesList = { - val parkingStall1: ParkingStall = ParkingStall.init[TAZ](dummyChargingZone, taz.tazId, taz.coord, 0.0) + val parkingStall1: ParkingStall = ParkingStall.init(dummyChargingZone, taz.tazId, taz.coord, 0.0) val v1 = new BeamVehicle( Id.createVehicleId("id1"), new Powertrain(0.0), @@ -128,13 +128,13 @@ class SitePowerManagerSpec List((v1, person1), (v2, person2)) } - val chargingNetwork: ChargingNetwork[TAZ] = ChargingNetwork.init( + val chargingNetwork: ChargingNetwork = ChargingNetwork.init( Map(dummyChargingZone.parkingZoneId -> dummyChargingZone), envelopeInUTM, beamServices ) - val rideHailNetwork: ChargingNetwork[TAZ] = ChargingNetwork.init( + val rideHailNetwork: ChargingNetwork = ChargingNetwork.init( Map(), envelopeInUTM, beamServices diff --git a/src/test/scala/beam/router/BeamRouterSpec.scala b/src/test/scala/beam/router/BeamRouterSpec.scala index a88cb1e4e5d..29fcda7c1a6 100644 --- a/src/test/scala/beam/router/BeamRouterSpec.scala +++ b/src/test/scala/beam/router/BeamRouterSpec.scala @@ -127,9 +127,6 @@ class BeamRouterSpec extends AnyFlatSpec with BeamScenarioForTest { trainStopQuadTree = new QuadTree[com.conveyal.gtfs.model.Stop](0.0, 0.0, 0.0, 0.0), tazTreeMap = tazMap, exchangeGeoMap = None, - linkQuadTree = new QuadTree[Link](0, 0, 10, 10), - linkIdMapping = Map.empty, - linkToTAZMapping = Map.empty, modeIncentives = null, h3taz = null, freightCarriers = IndexedSeq.empty, diff --git a/src/test/scala/beam/utils/BeamScenarioForTest.scala b/src/test/scala/beam/utils/BeamScenarioForTest.scala index 6b6de8470a6..9c5d8d85480 100644 --- a/src/test/scala/beam/utils/BeamScenarioForTest.scala +++ b/src/test/scala/beam/utils/BeamScenarioForTest.scala @@ -65,9 +65,6 @@ trait BeamScenarioForTest extends AnyFlatSpec { trainStopQuadTree = new QuadTree[Stop](0, 0, 10, 10), tazTreeMap = tazMap, exchangeGeoMap = None, - linkQuadTree = new QuadTree[Link](0, 0, 10, 10), - linkIdMapping = Map.empty, - linkToTAZMapping = Map.empty, modeIncentives = null, h3taz = null, freightCarriers = null, diff --git a/src/test/scala/beam/utils/GeoUtilsTest.scala b/src/test/scala/beam/utils/GeoUtilsTest.scala index ba4c13465d2..0694a807d7c 100644 --- a/src/test/scala/beam/utils/GeoUtilsTest.scala +++ b/src/test/scala/beam/utils/GeoUtilsTest.scala @@ -1,6 +1,7 @@ package beam.utils import beam.sim.common.GeoUtils +import org.matsim.api.core.v01.Coord import org.scalactic.{Equality, TolerantNumerics} import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers @@ -13,4 +14,24 @@ class GeoUtilsTest extends AnyFunSuite with Matchers { GeoUtils.distFormula(x1 = 1, y1 = 1, x2 = 2, y2 = 2) should equal(1.414214) GeoUtils.distFormula(x1 = 1, y1 = 3, x2 = 4, y2 = 7) should equal(5.0) } + + test("isPointWithinCircle should work properly") { + GeoUtils.isPointWithinCircle(new Coord(1, 2), 2 * 2, new Coord(0, 0)) shouldBe false + GeoUtils.isPointWithinCircle(new Coord(1, 2), 2.3 * 2.3, new Coord(0, 0)) shouldBe true + } + + test("segmentCircleIntersection should work properly") { + val i1 = GeoUtils.segmentCircleIntersection(new Coord(1, 0), 3, new Coord(2, 1)) + i1.getX shouldBe 3.121 +- 0.001 + i1.getY shouldBe 2.121 +- 0.001 + val i2 = GeoUtils.segmentCircleIntersection(new Coord(1, 0), 3, new Coord(-5, -6)) + i2.getX shouldBe -1.121 +- 0.001 + i2.getY shouldBe -2.121 +- 0.001 + val i3 = GeoUtils.segmentCircleIntersection(new Coord(1, 0), 3, new Coord(6, -5)) + i3.getX shouldBe 3.121 +- 0.001 + i3.getY shouldBe -2.121 +- 0.001 + val i4 = GeoUtils.segmentCircleIntersection(new Coord(2, 4), 4, new Coord(-4, 10)) + i4.getX shouldBe -0.828 +- 0.001 + i4.getY shouldBe 6.828 +- 0.001 + } } diff --git a/test/input/beamville/parking/link-parking.csv b/test/input/beamville/parking/link-parking.csv deleted file mode 100644 index 48aa969b3fe..00000000000 --- a/test/input/beamville/parking/link-parking.csv +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c40be58c261a8fdfd24d6445dd4c058156fb3f7f660bfe3285c2e137d15e5b9c -size 603219 diff --git a/test/input/sf-light/link-parking.csv.gz b/test/input/sf-light/link-parking.csv.gz deleted file mode 100644 index 90baf167b1b..00000000000 --- a/test/input/sf-light/link-parking.csv.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fc72ca12488c6d54abf07ac5134c56a9d0022456e7799b69cc96c4b84ffd78ec -size 10005205 diff --git a/test/input/sf-light/sf-light-1k-csv-linkparking-pickups-dropoffs.conf b/test/input/sf-light/sf-light-1k-csv-linkparking-pickups-dropoffs.conf deleted file mode 100755 index 90998e0d9eb..00000000000 --- a/test/input/sf-light/sf-light-1k-csv-linkparking-pickups-dropoffs.conf +++ /dev/null @@ -1,18 +0,0 @@ -include "sf-light-1k-csv.conf" - -beam.agentsim.simulationName = "sf-light-1k-csv-with-link-parking" - -beam.agentsim.firstIteration = 0 -beam.agentsim.lastIteration = 0 - -beam.agentsim.taz.parkingFilePath = "test/input/sf-light/link-parking.csv.gz" -beam.agentsim.taz.parkingManager.name = "HIERARCHICAL" - -beam.physsim.jdeqsim.cacc.enabled = false - -beam.physsim.pickUpDropOffAnalysis.enabled = true -beam.physsim.pickUpDropOffAnalysis.secondsFromPickUpPropOffToAffectTravelTime = 1 -beam.physsim.pickUpDropOffAnalysis.additionalTravelTimeMultiplier = 1.0 - -beam.physsim.writePlansInterval = 1 -beam.physsim.events.fileOutputFormats = "xml" diff --git a/test/input/sf-light/sf-light-25k-experiment-2.conf b/test/input/sf-light/sf-light-25k-experiment-2.conf deleted file mode 100755 index cac735ef57c..00000000000 --- a/test/input/sf-light/sf-light-25k-experiment-2.conf +++ /dev/null @@ -1,9 +0,0 @@ -include "sf-light-25k-experiment-1.conf" - -beam.agentsim.simulationName = "sf-light-25k-linkparking" - -beam.agentsim.taz.parkingFilePath = "test/input/sf-light/link-parking.csv.gz" -beam.agentsim.taz.parkingManager.name = "HIERARCHICAL" - - - diff --git a/test/input/sf-light/sf-light-25k-experiment-3.conf b/test/input/sf-light/sf-light-25k-experiment-3.conf deleted file mode 100755 index 90137253793..00000000000 --- a/test/input/sf-light/sf-light-25k-experiment-3.conf +++ /dev/null @@ -1,13 +0,0 @@ -include "sf-light-25k-experiment-1.conf" - -beam.agentsim.simulationName = "sf-light-25k-linkparking-light-pd" - -beam.agentsim.taz.parkingFilePath = "test/input/sf-light/link-parking.csv.gz" -beam.agentsim.taz.parkingManager.name = "HIERARCHICAL" - -beam.physsim.pickUpDropOffAnalysis.enabled = true -beam.physsim.pickUpDropOffAnalysis.secondsFromPickUpPropOffToAffectTravelTime = 60 -beam.physsim.pickUpDropOffAnalysis.additionalTravelTimeMultiplier = 1.0 - - - diff --git a/test/input/sf-light/sf-light-25k-experiment-4.conf b/test/input/sf-light/sf-light-25k-experiment-4.conf deleted file mode 100755 index f9c84ebe48a..00000000000 --- a/test/input/sf-light/sf-light-25k-experiment-4.conf +++ /dev/null @@ -1,12 +0,0 @@ -include "sf-light-25k-experiment-1.conf" - -beam.agentsim.simulationName = "sf-light-25k-linkparking-medium-pd" - -beam.agentsim.taz.parkingFilePath = "test/input/sf-light/link-parking.csv.gz" -beam.agentsim.taz.parkingManager.name = "HIERARCHICAL" - -beam.physsim.pickUpDropOffAnalysis.enabled = true -beam.physsim.pickUpDropOffAnalysis.secondsFromPickUpPropOffToAffectTravelTime = 600 -beam.physsim.pickUpDropOffAnalysis.additionalTravelTimeMultiplier = 2.0 - - diff --git a/test/input/sf-light/sf-light-25k-experiment-5.conf b/test/input/sf-light/sf-light-25k-experiment-5.conf deleted file mode 100755 index dcfe7ac4f1e..00000000000 --- a/test/input/sf-light/sf-light-25k-experiment-5.conf +++ /dev/null @@ -1,12 +0,0 @@ -include "sf-light-25k-experiment-1.conf" - -beam.agentsim.simulationName = "sf-light-25k-linkparking-heavy-pd" - -beam.agentsim.taz.parkingFilePath = "test/input/sf-light/link-parking.csv.gz" -beam.agentsim.taz.parkingManager.name = "HIERARCHICAL" - -beam.physsim.pickUpDropOffAnalysis.enabled = true -beam.physsim.pickUpDropOffAnalysis.secondsFromPickUpPropOffToAffectTravelTime = 6000 -beam.physsim.pickUpDropOffAnalysis.additionalTravelTimeMultiplier = 5.0 - - From a3c4c6b08a93715c2ecf2544313038388a83ca1e Mon Sep 17 00:00:00 2001 From: Justin Pihony Date: Sat, 7 May 2022 13:33:31 -0400 Subject: [PATCH 24/25] use submodules for caching --- .../python/updateDependencies/lambda_function.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/aws/src/main/python/updateDependencies/lambda_function.py b/aws/src/main/python/updateDependencies/lambda_function.py index a8fc4b568f0..6c1642a92f8 100644 --- a/aws/src/main/python/updateDependencies/lambda_function.py +++ b/aws/src/main/python/updateDependencies/lambda_function.py @@ -61,8 +61,12 @@ - echo "-------------------checkout $bn----------------------" - sudo GIT_LFS_SKIP_SMUDGE=1 git checkout $bn - sudo git reset --hard origin/$bn - - sudo git pull - - sudo git lfs pull + - for submodule in $SUBMODULES + - do + - sudo git submodule update --init --remote $submodule + - sudo git pull + - sudo git lfs pull + - done - done - sudo chown -R ubuntu:ubuntu /home/ubuntu/git/beam - echo "gradlew assemble ..." @@ -70,7 +74,7 @@ - ./gradlew clean - echo "preparing for python analysis" - 'echo resetting git to base: "$(date)"' - - sudo git reset --hard + - sudo git reset --hard - 'echo fetching the latest: "$(date)"' - sudo git fetch - 'echo current git status: "$(date)"' @@ -134,8 +138,9 @@ def lambda_handler(event, context): shutdown_wait = "10" runName = 'update-beam-dependencies' branches = os.environ['BRANCHES'] + submodules = os.environ['SUBMODULES'] - script = initscript.replace('$BRANCH', branches).replace('$SHUTDOWN_WAIT', shutdown_wait) + script = initscript.replace('$BRANCH', branches).replace('$SHUTDOWN_WAIT', shutdown_wait).replace('$SUBMODULES', submodules) init_ec2(region) instance_id = deploy(script, instance_type, region.replace("-", "_")+'_', shutdown_behaviour, runName, en_vars) From 1c71434fb8625f645288f64dd9d083e9c06de82c Mon Sep 17 00:00:00 2001 From: Justin Pihony Date: Mon, 9 May 2022 00:53:32 -0400 Subject: [PATCH 25/25] Save config --- .../updateDependencies.yaml | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 aws/src/main/python/updateDependencies/updateDependencies.yaml diff --git a/aws/src/main/python/updateDependencies/updateDependencies.yaml b/aws/src/main/python/updateDependencies/updateDependencies.yaml new file mode 100644 index 00000000000..67f453043ef --- /dev/null +++ b/aws/src/main/python/updateDependencies/updateDependencies.yaml @@ -0,0 +1,24 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: 'AWS::Serverless-2016-10-31' +Description: An AWS Serverless Specification template describing your function. +Resources: + updateDependencies: + Type: 'AWS::Serverless::Function' + Properties: + Handler: lambda_function.lambda_handler + Runtime: python2.7 + CodeUri: . + Description: '' + MemorySize: 128 + Timeout: 300 + Role: 'arn:aws:iam::340032650202:role/BeamLambdaExecution' + Events: + Schedule1: + Type: Schedule + Properties: + Schedule: rate(4 days) + Environment: + Variables: + BRANCHES: master develop freight-develop hl/gemini-develop gemini-develop + INSTANCE_TYPE: t2.small + SUBMODULES: production/newyork production/sfbay production/austin