View Javadoc
1   package org.opentrafficsim.road.gtu.strategical.od;
2   
3   import java.util.List;
4   
5   import org.djunits.unit.DurationUnit;
6   import org.djunits.unit.FrequencyUnit;
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-2017 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] = trips[i]
90                          / (timeVector.get(i + 1).getInUnit(DurationUnit.HOUR) - timeVector.get(i).getInUnit(DurationUnit.HOUR));
91              }
92              // last value can remain zero as initialized
93              putDemandVector(origin, destination, category, new FrequencyVector(flow, FrequencyUnit.PER_HOUR, StorageType.DENSE),
94                      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),
163                     time.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, final int periodIndex,
187             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 = trips / (time.get(periodIndex + 1).getInUnit(DurationUnit.HOUR)
199                     - time.get(periodIndex).getInUnit(DurationUnit.HOUR));
200             double[] dem = demand.getValuesInUnit(FrequencyUnit.PER_HOUR);
201             dem[periodIndex] += additionalDemand;
202             putDemandVector(origin, destination, category, new FrequencyVector(dem, FrequencyUnit.PER_HOUR, StorageType.DENSE),
203                     time, Interpolation.STEPWISE);
204         }
205         catch (ValueException exception)
206         {
207             // should not happen as the index was checked
208             throw new RuntimeException("Could not get number of trips.", exception);
209         }
210     }
211 
212     /**
213      * Calculates total number of trips over time for given origin.
214      * @param origin origin
215      * @return total number of trips over time for given origin
216      * @throws IllegalArgumentException if origin is not part of the OD matrix
217      * @throws NullPointerException if origin is null
218      */
219     public final int originTotal(final Node origin)
220     {
221         int sum = 0;
222         for (Node destination : getDestinations())
223         {
224             sum += originDestinationTotal(origin, destination);
225         }
226         return sum;
227     }
228 
229     /**
230      * Calculates total number of trips over time for given destination.
231      * @param destination destination
232      * @return total number of trips over time for given destination
233      * @throws IllegalArgumentException if destination is not part of the OD matrix
234      * @throws NullPointerException if destination is null
235      */
236     public final int destinationTotal(final Node destination)
237     {
238         int sum = 0;
239         for (Node origin : getOrigins())
240         {
241             sum += originDestinationTotal(origin, destination);
242         }
243         return sum;
244     }
245 
246     /**
247      * Calculates total number of trips over time for the complete matrix.
248      * @return total number of trips over time for the complete matrix
249      */
250     public final int matrixTotal()
251     {
252         int sum = 0;
253         for (Node origin : getOrigins())
254         {
255             for (Node destination : getDestinations())
256             {
257                 sum += originDestinationTotal(origin, destination);
258             }
259         }
260         return sum;
261     }
262 
263     /**
264      * Calculates total number of trips over time for given origin-destination combination.
265      * @param origin origin
266      * @param destination destination
267      * @return total number of trips over time for given origin-destination combination
268      * @throws IllegalArgumentException if origin or destination is not part of the OD matrix
269      * @throws NullPointerException if an input is null
270      */
271     public final int originDestinationTotal(final Node origin, final Node destination)
272     {
273         int sum = 0;
274         for (Category category : getCategories(origin, destination))
275         {
276             DurationVector time = getTimeVector(origin, destination, category);
277             FrequencyVector demand = getDemandVector(origin, destination, category);
278             Interpolation interpolation = getInterpolation(origin, destination, category);
279             for (int i = 0; i < time.size() - 1; i++)
280             {
281                 try
282                 {
283                     sum += interpolation.integrate(demand.get(i), time.get(i), demand.get(i + 1), time.get(i + 1));
284                 }
285                 catch (ValueException exception)
286                 {
287                     // should not happen as we loop over the array length
288                     throw new RuntimeException("Could not determine total trips over time.", exception);
289                 }
290             }
291         }
292         return sum;
293     }
294 
295     /** {@inheritDoc} */
296     public final String toString()
297     {
298         return "ODMatrixTrips [" + getOrigins().size() + " origins, " + getDestinations().size() + " destinations, "
299                 + getCategorization() + " ]";
300     }
301 
302 }