View Javadoc
1   package org.opentrafficsim.road.gtu.strategical.od;
2   
3   import java.util.List;
4   
5   import org.djunits.unit.FrequencyUnit;
6   import org.djunits.unit.TimeUnit;
7   import org.djunits.value.StorageType;
8   import org.djunits.value.ValueException;
9   import org.djunits.value.vdouble.vector.DurationVector;
10  import org.djunits.value.vdouble.vector.FrequencyVector;
11  import org.opentrafficsim.core.network.Node;
12  
13  import nl.tudelft.simulation.language.Throw;
14  
15  /**
16   * Extension of ODMatrix where all input and output can be given in number of trips. All data that is defined in number of trips
17   * has Interpolation.STEPWISE.
18   * <p>
19   * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
20   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
21   * <p>
22   * @version $Revision$, $LastChangedDate$, by $Author$, initial version Sep 28, 2016 <br>
23   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
24   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
25   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
26   */
27  // TODO pce (i.e. passenger car equivalent) instead of veh's
28  public class ODMatrixTrips extends ODMatrix
29  {
30  
31      /** */
32      private static final long serialVersionUID = 20160928L;
33  
34      /**
35       * Constructs an OD matrix based on trips.
36       * @param id id
37       * @param origins origin nodes
38       * @param destinations destination nodes
39       * @param categorization categorization of data
40       * @param globalTimeVector default time
41       * @param globalInterpolation interpolation of demand data
42       * @throws NullPointerException if any input is null
43       */
44      public ODMatrixTrips(final String id, final List<Node> origins, final List<Node> destinations,
45          final Categorization categorization, final DurationVector globalTimeVector, final Interpolation globalInterpolation)
46      {
47          super(id, origins, destinations, categorization, globalTimeVector, globalInterpolation);
48      }
49  
50      /**
51       * @param origin origin
52       * @param destination destination
53       * @param category category
54       * @param trips trip data, length has to be equal to the global time vector - 1
55       * @throws IllegalArgumentException if origin or destination is not part of the OD matrix
56       * @throws IllegalArgumentException if the category does not belong to the categorization
57       * @throws NullPointerException if an input is null
58       */
59      public final void putTripsVector(final Node origin, final Node destination, final Category category, final int[] trips)
60      {
61          putTripsVector(origin, destination, category, trips, getGlobalTimeVector());
62      }
63  
64      /**
65       * Sets demand data by number of trips. Interpolation over time is stepwise.
66       * @param origin origin
67       * @param destination destination
68       * @param category category
69       * @param trips trip data, length has to be equal to the time vector - 1
70       * @param timeVector time vector
71       * @throws IllegalArgumentException if origin or destination is not part of the OD matrix
72       * @throws IllegalArgumentException if the category does not belong to the categorization
73       * @throws NullPointerException if an input is null
74       */
75      public final void putTripsVector(final Node origin, final Node destination, final Category category, final int[] trips,
76          final DurationVector timeVector)
77      {
78          // this is what we need here, other checks in putDemandVector
79          Throw.whenNull(trips, "Demand data may not be null.");
80          Throw.whenNull(timeVector, "Time vector may not be null.");
81          Throw.when(trips.length != timeVector.size() - 1, IllegalArgumentException.class,
82              "Trip data and time data have wrong lengths. Trip data should be 1 shorter than time data.");
83          // convert to flow
84          double[] flow = new double[timeVector.size()];
85          try
86          {
87              for (int i = 0; i < trips.length; i++)
88              {
89                  flow[i] =
90                      trips[i] / (timeVector.get(i + 1).getInUnit(TimeUnit.HOUR) - timeVector.get(i).getInUnit(TimeUnit.HOUR));
91              }
92              // last value can remain zero as initialized
93              putDemandVector(origin, destination, category, new FrequencyVector(flow, FrequencyUnit.PER_HOUR,
94                  StorageType.DENSE), timeVector, Interpolation.STEPWISE);
95          }
96          catch (ValueException exception)
97          {
98              // should not happen as we check and then loop over the array length
99              throw new RuntimeException("Could not translate trip vector into demand vector.", exception);
100         }
101     }
102 
103     /**
104      * @param origin origin
105      * @param destination destination
106      * @param category category
107      * @return trip data for given origin, destination and categorization, {@code null} if no data is given
108      * @throws IllegalArgumentException if origin or destination is not part of the OD matrix
109      * @throws IllegalArgumentException if the category does not belong to the categorization
110      * @throws NullPointerException if an input is null
111      */
112     public final int[] getTripsVector(final Node origin, final Node destination, final Category category)
113     {
114         FrequencyVector demand = getDemandVector(origin, destination, category);
115         if (demand == null)
116         {
117             return null;
118         }
119         int[] trips = new int[demand.size() - 1];
120         DurationVector time = getTimeVector(origin, destination, category);
121         Interpolation interpolation = getInterpolation(origin, destination, category);
122         for (int i = 0; i < trips.length; i++)
123         {
124             try
125             {
126                 trips[i] = interpolation.integrate(demand.get(i), time.get(i), demand.get(i + 1), time.get(i + 1));
127             }
128             catch (ValueException exception)
129             {
130                 // should not happen as we loop over the array length
131                 throw new RuntimeException("Could not translate demand vector into trip vector.", exception);
132             }
133         }
134         return trips;
135     }
136 
137     /**
138      * Returns the number of trips in the given time period.
139      * @param origin origin
140      * @param destination destination
141      * @param category category
142      * @param periodIndex index of time period
143      * @return demand for given origin, destination and categorization, at given time
144      * @throws IllegalArgumentException if origin or destination is not part of the OD matrix
145      * @throws IllegalArgumentException if the category does not belong to the categorization
146      * @throws IllegalArgumentException if the period is outside of the specified range
147      * @throws NullPointerException if an input is null
148      */
149     public final int getTrips(final Node origin, final Node destination, final Category category, final int periodIndex)
150     {
151         DurationVector time = getTimeVector(origin, destination, category);
152         if (time == null)
153         {
154             return 0;
155         }
156         Throw.when(periodIndex < 0 || periodIndex >= time.size() - 1, IllegalArgumentException.class,
157             "Period index out of range.");
158         FrequencyVector demand = getDemandVector(origin, destination, category);
159         Interpolation interpolation = getInterpolation(origin, destination, category);
160         try
161         {
162             return interpolation.integrate(demand.get(periodIndex), time.get(periodIndex), demand.get(periodIndex + 1), time
163                 .get(periodIndex + 1));
164         }
165         catch (ValueException exception)
166         {
167             // should not happen as the index was checked
168             throw new RuntimeException("Could not get number of trips.", exception);
169         }
170     }
171 
172     /**
173      * Adds a number of trips to given origin-destination combination, category and time period. This can only be done for data
174      * with stepwise interpolation.
175      * @param origin origin
176      * @param destination destination
177      * @param category category
178      * @param periodIndex index of time period
179      * @param trips trips to add (may be negative)
180      * @throws IllegalArgumentException if origin or destination is not part of the OD matrix
181      * @throws IllegalArgumentException if the category does not belong to the categorization
182      * @throws IllegalArgumentException if the period is outside of the specified range
183      * @throws UnsupportedOperationException if the interpolation of the data is not stepwise
184      * @throws NullPointerException if an input is null
185      */
186     public final void increaseTrips(final Node origin, final Node destination, final Category category,
187         final int periodIndex, final int trips)
188     {
189         Interpolation interpolation = getInterpolation(origin, destination, category);
190         Throw.when(!interpolation.equals(Interpolation.STEPWISE), UnsupportedOperationException.class,
191             "Can only increase the number of trips for data with stepwise interpolation.");
192         DurationVector time = getTimeVector(origin, destination, category);
193         Throw.when(periodIndex < 0 || periodIndex >= time.size() - 1, IllegalArgumentException.class,
194             "Period index out of range.");
195         FrequencyVector demand = getDemandVector(origin, destination, category);
196         try
197         {
198             double additionalDemand =
199                 trips
200                     / (time.get(periodIndex + 1).getInUnit(TimeUnit.HOUR) - time.get(periodIndex).getInUnit(TimeUnit.HOUR));
201             double[] dem = demand.getValuesInUnit(FrequencyUnit.PER_HOUR);
202             dem[periodIndex] += additionalDemand;
203             putDemandVector(origin, destination, category, new FrequencyVector(dem, FrequencyUnit.PER_HOUR,
204                 StorageType.DENSE), time, Interpolation.STEPWISE);
205         }
206         catch (ValueException exception)
207         {
208             // should not happen as the index was checked
209             throw new RuntimeException("Could not get number of trips.", exception);
210         }
211     }
212 
213     /**
214      * Calculates total number of trips over time for given origin.
215      * @param origin origin
216      * @return total number of trips over time for given origin
217      * @throws IllegalArgumentException if origin is not part of the OD matrix
218      * @throws NullPointerException if origin is null
219      */
220     public final int originTotal(final Node origin)
221     {
222         int sum = 0;
223         for (Node destination : getDestinations())
224         {
225             sum += originDestinationTotal(origin, destination);
226         }
227         return sum;
228     }
229 
230     /**
231      * Calculates total number of trips over time for given destination.
232      * @param destination destination
233      * @return total number of trips over time for given destination
234      * @throws IllegalArgumentException if destination is not part of the OD matrix
235      * @throws NullPointerException if destination is null
236      */
237     public final int destinationTotal(final Node destination)
238     {
239         int sum = 0;
240         for (Node origin : getOrigins())
241         {
242             sum += originDestinationTotal(origin, destination);
243         }
244         return sum;
245     }
246 
247     /**
248      * Calculates total number of trips over time for the complete matrix.
249      * @return total number of trips over time for the complete matrix
250      */
251     public final int matrixTotal()
252     {
253         int sum = 0;
254         for (Node origin : getOrigins())
255         {
256             for (Node destination : getDestinations())
257             {
258                 sum += originDestinationTotal(origin, destination);
259             }
260         }
261         return sum;
262     }
263 
264     /**
265      * Calculates total number of trips over time for given origin-destination combination.
266      * @param origin origin
267      * @param destination destination
268      * @return total number of trips over time for given origin-destination combination
269      * @throws IllegalArgumentException if origin or destination is not part of the OD matrix
270      * @throws NullPointerException if an input is null
271      */
272     public final int originDestinationTotal(final Node origin, final Node destination)
273     {
274         int sum = 0;
275         for (Category category : getCategories(origin, destination))
276         {
277             DurationVector time = getTimeVector(origin, destination, category);
278             FrequencyVector demand = getDemandVector(origin, destination, category);
279             Interpolation interpolation = getInterpolation(origin, destination, category);
280             for (int i = 0; i < time.size() - 1; i++)
281             {
282                 try
283                 {
284                     sum += interpolation.integrate(demand.get(i), time.get(i), demand.get(i + 1), time.get(i + 1));
285                 }
286                 catch (ValueException exception)
287                 {
288                     // should not happen as we loop over the array length
289                     throw new RuntimeException("Could not determine total trips over time.", exception);
290                 }
291             }
292         }
293         return sum;
294     }
295 
296     /** {@inheritDoc} */
297     public final String toString()
298     {
299         return "ODMatrixTrips [" + getOrigins().size() + " origins, " + getDestinations().size() + " destinations, "
300             + getCategorization() + " ]";
301     }
302 
303 }