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}