001/* *********************************************************************** * 002 * project: org.matsim.* 003 * LanesUtils 004 * * 005 * *********************************************************************** * 006 * * 007 * copyright : (C) 2012 by the members listed in the COPYING, * 008 * LICENSE and WARRANTY file. * 009 * email : info at matsim dot org * 010 * * 011 * *********************************************************************** * 012 * * 013 * This program is free software; you can redistribute it and/or modify * 014 * it under the terms of the GNU General Public License as published by * 015 * the Free Software Foundation; either version 2 of the License, or * 016 * (at your option) any later version. * 017 * See also COPYING, LICENSE and WARRANTY file * 018 * * 019 * *********************************************************************** */ 020package org.matsim.lanes; 021 022import org.matsim.api.core.v01.Id; 023import org.matsim.api.core.v01.Scenario; 024import org.matsim.api.core.v01.network.Link; 025import org.matsim.api.core.v01.network.Network; 026import org.matsim.core.config.Config; 027import org.matsim.core.config.ConfigUtils; 028import org.matsim.core.scenario.ScenarioUtils; 029 030import java.util.*; 031 032/** 033 * @author dgrether 034 * @author tthunig 035 * 036 */ 037public final class LanesUtils { 038 039 public static Lanes createLanesContainer(){ 040 return new LanesImpl(); 041 } 042 043 /** 044 * Convenience method to create a lane with the given Id, the given length, 045 * the given capacity, the given number of represented lanes, the given 046 * alignment and the given Ids of the downstream links or lanes, respectively, 047 * the lane leads to. The lane is added to the LanesToLinkAssignment given 048 * as parameter. 049 * 050 * @param l2l 051 * the LanesToLinkAssignment to that the created lane is added 052 * @param factory 053 * a LaneDefinitionsFactory to create the lane 054 * @param laneId 055 * @param capacity 056 * @param startsAtMeterFromLinkEnd 057 * @param alignment 058 * @param numberOfRepresentedLanes 059 * @param toLinkIds 060 * @param toLaneIds 061 */ 062 public static void createAndAddLane(LanesToLinkAssignment l2l, 063 LanesFactory factory, Id<Lane> laneId, double capacity, 064 double startsAtMeterFromLinkEnd, int alignment, 065 int numberOfRepresentedLanes, List<Id<Link>> toLinkIds, List<Id<Lane>> toLaneIds) { 066 067 Lane lane = factory.createLane(laneId); 068 if (toLinkIds != null){ 069 for (Id<Link> toLinkId : toLinkIds) { 070 lane.addToLinkId(toLinkId); 071 } 072 } 073 if (toLaneIds != null){ 074 for (Id<Lane> toLaneId : toLaneIds) { 075 lane.addToLaneId(toLaneId); 076 } 077 } 078 lane.setCapacityVehiclesPerHour(capacity); 079 lane.setStartsAtMeterFromLinkEnd(startsAtMeterFromLinkEnd); 080 lane.setNumberOfRepresentedLanes(numberOfRepresentedLanes); 081 lane.setAlignment(alignment); 082 l2l.addLane(lane); 083 } 084 085 /** 086 * Replaces the method that converted a lane from format 11 to format 20. 087 * Use this when you have not defined an original lane of the link and when you have not set lane capacities yet. 088 */ 089 public static void createOriginalLanesAndSetLaneCapacities(Network network, Lanes lanes){ 090 LanesFactory factory = lanes.getFactory(); 091 for (LanesToLinkAssignment l2l : lanes.getLanesToLinkAssignments().values()){ 092 Link link = network.getLinks().get(l2l.getLinkId()); 093 094 Lane olLane = factory.createLane(Id.create(l2l.getLinkId().toString() + ".ol", Lane.class)); 095 l2l.addLane(olLane); 096 for (Lane lane : l2l.getLanes().values()) { 097 olLane.addToLaneId(lane.getId()); 098 099 //set capacity of the lane depending on link capacity and number of representative lanes 100 LanesUtils.calculateAndSetCapacity(lane, true, link, network); 101 } 102 olLane.setNumberOfRepresentedLanes(link.getNumberOfLanes()); 103 olLane.setStartsAtMeterFromLinkEnd(link.getLength()); 104 } 105 } 106 107 /** 108 * Creates a sorted list of lanes for a link. 109 * @param link 110 * @param lanesToLinkAssignment 111 * @return sorted list with the most upstream lane at the first position. 112 */ 113 public static List<ModelLane> createLanes(Link link, LanesToLinkAssignment lanesToLinkAssignment) { 114 List<ModelLane> queueLanes = new ArrayList<>(); 115 List<Lane> sortedLanes = new ArrayList<>(lanesToLinkAssignment.getLanes().values()); 116 Collections.sort(sortedLanes, new Comparator<Lane>() { 117 @Override 118 public int compare(Lane o1, Lane o2) { 119 if (o1.getStartsAtMeterFromLinkEnd() < o2.getStartsAtMeterFromLinkEnd()) { 120 return -1; 121 } else if (o1.getStartsAtMeterFromLinkEnd() > o2.getStartsAtMeterFromLinkEnd()) { 122 return 1; 123 } else { 124 return 0; 125 } 126 } 127 }); 128 Collections.reverse(sortedLanes); 129 130 List<ModelLane> laneList = new LinkedList<>(); 131 Lane firstLane = sortedLanes.remove(0); 132 if (firstLane.getStartsAtMeterFromLinkEnd() != link.getLength()) { 133 throw new IllegalStateException("First Lane Id " + firstLane.getId() + " on Link Id " + link.getId() + 134 "isn't starting at the beginning of the link!"); 135 } 136 ModelLane firstQLane = new ModelLane(firstLane); 137 laneList.add(firstQLane); 138 Stack<ModelLane> laneStack = new Stack<>(); 139 140 while (!laneList.isEmpty()){ 141 ModelLane lastQLane = laneList.remove(0); 142 laneStack.push(lastQLane); 143 queueLanes.add(lastQLane); 144 145 //if existing create the subsequent lanes 146 List<Id<Lane>> toLaneIds = lastQLane.getLaneData().getToLaneIds(); 147 double nextMetersFromLinkEnd = 0.0; 148 double laneLength = 0.0; 149 if (toLaneIds != null && (!toLaneIds.isEmpty())) { 150 for (Id<Lane> toLaneId : toLaneIds){ 151 Lane currentLane = lanesToLinkAssignment.getLanes().get(toLaneId); 152 nextMetersFromLinkEnd = currentLane.getStartsAtMeterFromLinkEnd(); 153 ModelLane currentQLane = new ModelLane(currentLane); 154 laneList.add(currentQLane); 155 lastQLane.addAToLane(currentQLane); 156 } 157 laneLength = lastQLane.getLaneData().getStartsAtMeterFromLinkEnd() - nextMetersFromLinkEnd; 158 lastQLane.setEndsAtMetersFromLinkEnd(nextMetersFromLinkEnd); 159 } 160 //there are no subsequent lanes 161 else { 162 laneLength = lastQLane.getLaneData().getStartsAtMeterFromLinkEnd(); 163 lastQLane.setEndsAtMetersFromLinkEnd(0.0); 164 } 165 lastQLane.setLength(laneLength); 166 } 167 168 //fill toLinks 169 while (! laneStack.isEmpty()){ 170 ModelLane qLane = laneStack.pop(); 171 if (qLane.getToLanes() == null || (qLane.getToLanes().isEmpty())) { 172 for (Id<Link> toLinkId : qLane.getLaneData().getToLinkIds()){ 173 qLane.addDestinationLink(toLinkId); 174 } 175 } 176 else { 177 for (ModelLane subsequentLane : qLane.getToLanes()){ 178 for (Id<Link> toLinkId : subsequentLane.getDestinationLinkIds()){ 179 qLane.addDestinationLink(toLinkId); 180 } 181 } 182 } 183 } 184 185 Collections.sort(queueLanes, new Comparator<ModelLane>() { 186 @Override 187 public int compare(ModelLane o1, ModelLane o2) { 188 if (o1.getEndsAtMeterFromLinkEnd() < o2.getEndsAtMeterFromLinkEnd()) { 189 return -1; 190 } else if (o1.getEndsAtMeterFromLinkEnd() > o2.getEndsAtMeterFromLinkEnd()) { 191 return 1; 192 } else { 193 return 0; 194 } 195 } 196 }); 197 return queueLanes; 198 } 199 200 /** 201 * Calculate capacity by formular from Neumann2008DA: 202 * 203 * Flow of a Lane is given by the flow of the link divided by the number of lanes represented by the link. 204 * 205 * A Lane may represent one or more lanes in reality. This is given by the attribute numberOfRepresentedLanes of 206 * the Lane definition. The flow of a lane is scaled by this number. 207 */ 208 public static void calculateAndSetCapacity(Lane lane, boolean isLaneAtLinkEnd, Link link, Network network){ 209 if (isLaneAtLinkEnd){ 210 double noLanesLink = link.getNumberOfLanes(); 211 double linkFlowCapPerSecondPerLane = link.getCapacity() / network.getCapacityPeriod() 212 / noLanesLink; 213 double laneFlowCapPerHour = lane.getNumberOfRepresentedLanes() 214 * linkFlowCapPerSecondPerLane * 3600.0; 215 lane.setCapacityVehiclesPerHour(laneFlowCapPerHour); 216 } 217 else { 218 double capacity = link.getCapacity() / network.getCapacityPeriod() * 3600.0; 219 lane.setCapacityVehiclesPerHour(capacity); 220 } 221 } 222 223 public static void calculateMissingCapacitiesForLanes20(String networkInputFilename, String lanes20InputFilename, String lanes20OutputFilename){ 224 Config config = ConfigUtils.createConfig(); 225 config.network().setInputFile(networkInputFilename); 226 config.qsim().setUseLanes(true); 227 config.network().setLaneDefinitionsFile(lanes20InputFilename); 228 Scenario scenario = ScenarioUtils.loadScenario(config); 229 Network network = scenario.getNetwork(); 230 Lanes lanes = scenario.getLanes(); 231 for (LanesToLinkAssignment l2l : lanes.getLanesToLinkAssignments().values()){ 232 Link link = network.getLinks().get(l2l.getLinkId()); 233 for (Lane lane : l2l.getLanes().values()){ 234 if (lane.getToLaneIds() == null || lane.getToLaneIds().isEmpty()){ 235 calculateAndSetCapacity(lane, true, link, network); 236 } 237 else { 238 calculateAndSetCapacity(lane, false, link, network); 239 } 240 } 241 } 242 LanesWriter writerDelegate = new LanesWriter(lanes); 243 writerDelegate.write(lanes20OutputFilename); 244 } 245 246 public static void overwriteLaneCapacitiesByNetworkCapacities(Network net, Lanes lanes) { 247 for (LanesToLinkAssignment linkLanes : lanes.getLanesToLinkAssignments().values()) { 248 double linkCap = net.getLinks().get(linkLanes.getLinkId()).getCapacity(); 249 for (Lane lane : linkLanes.getLanes().values()) { 250 lane.setCapacityVehiclesPerHour(linkCap); 251 } 252 } 253 } 254}