ODMatrixTrips.java
package org.opentrafficsim.road.gtu.strategical.od;
import java.util.List;
import org.djunits.unit.FrequencyUnit;
import org.djunits.unit.TimeUnit;
import org.djunits.value.StorageType;
import org.djunits.value.ValueException;
import org.djunits.value.vdouble.vector.DurationVector;
import org.djunits.value.vdouble.vector.FrequencyVector;
import org.opentrafficsim.core.network.Node;
import nl.tudelft.simulation.language.Throw;
/**
* Extension of ODMatrix where all input and output can be given in number of trips. All data that is defined in number of trips
* has Interpolation.STEPWISE.
* <p>
* Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
* BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
* <p>
* @version $Revision$, $LastChangedDate$, by $Author$, initial version Sep 28, 2016 <br>
* @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
* @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
* @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
*/
// TODO pce (i.e. passenger car equivalent) instead of veh's
public class ODMatrixTrips extends ODMatrix
{
/** */
private static final long serialVersionUID = 20160928L;
/**
* Constructs an OD matrix based on trips.
* @param id id
* @param origins origin nodes
* @param destinations destination nodes
* @param categorization categorization of data
* @param globalTimeVector default time
* @param globalInterpolation interpolation of demand data
* @throws NullPointerException if any input is null
*/
public ODMatrixTrips(final String id, final List<Node> origins, final List<Node> destinations,
final Categorization categorization, final DurationVector globalTimeVector, final Interpolation globalInterpolation)
{
super(id, origins, destinations, categorization, globalTimeVector, globalInterpolation);
}
/**
* @param origin origin
* @param destination destination
* @param category category
* @param trips trip data, length has to be equal to the global time vector - 1
* @throws IllegalArgumentException if origin or destination is not part of the OD matrix
* @throws IllegalArgumentException if the category does not belong to the categorization
* @throws NullPointerException if an input is null
*/
public final void putTripsVector(final Node origin, final Node destination, final Category category, final int[] trips)
{
putTripsVector(origin, destination, category, trips, getGlobalTimeVector());
}
/**
* Sets demand data by number of trips. Interpolation over time is stepwise.
* @param origin origin
* @param destination destination
* @param category category
* @param trips trip data, length has to be equal to the time vector - 1
* @param timeVector time vector
* @throws IllegalArgumentException if origin or destination is not part of the OD matrix
* @throws IllegalArgumentException if the category does not belong to the categorization
* @throws NullPointerException if an input is null
*/
public final void putTripsVector(final Node origin, final Node destination, final Category category, final int[] trips,
final DurationVector timeVector)
{
// this is what we need here, other checks in putDemandVector
Throw.whenNull(trips, "Demand data may not be null.");
Throw.whenNull(timeVector, "Time vector may not be null.");
Throw.when(trips.length != timeVector.size() - 1, IllegalArgumentException.class,
"Trip data and time data have wrong lengths. Trip data should be 1 shorter than time data.");
// convert to flow
double[] flow = new double[timeVector.size()];
try
{
for (int i = 0; i < trips.length; i++)
{
flow[i] =
trips[i] / (timeVector.get(i + 1).getInUnit(TimeUnit.HOUR) - timeVector.get(i).getInUnit(TimeUnit.HOUR));
}
// last value can remain zero as initialized
putDemandVector(origin, destination, category, new FrequencyVector(flow, FrequencyUnit.PER_HOUR,
StorageType.DENSE), timeVector, Interpolation.STEPWISE);
}
catch (ValueException exception)
{
// should not happen as we check and then loop over the array length
throw new RuntimeException("Could not translate trip vector into demand vector.", exception);
}
}
/**
* @param origin origin
* @param destination destination
* @param category category
* @return trip data for given origin, destination and categorization, {@code null} if no data is given
* @throws IllegalArgumentException if origin or destination is not part of the OD matrix
* @throws IllegalArgumentException if the category does not belong to the categorization
* @throws NullPointerException if an input is null
*/
public final int[] getTripsVector(final Node origin, final Node destination, final Category category)
{
FrequencyVector demand = getDemandVector(origin, destination, category);
if (demand == null)
{
return null;
}
int[] trips = new int[demand.size() - 1];
DurationVector time = getTimeVector(origin, destination, category);
Interpolation interpolation = getInterpolation(origin, destination, category);
for (int i = 0; i < trips.length; i++)
{
try
{
trips[i] = interpolation.integrate(demand.get(i), time.get(i), demand.get(i + 1), time.get(i + 1));
}
catch (ValueException exception)
{
// should not happen as we loop over the array length
throw new RuntimeException("Could not translate demand vector into trip vector.", exception);
}
}
return trips;
}
/**
* Returns the number of trips in the given time period.
* @param origin origin
* @param destination destination
* @param category category
* @param periodIndex index of time period
* @return demand for given origin, destination and categorization, at given time
* @throws IllegalArgumentException if origin or destination is not part of the OD matrix
* @throws IllegalArgumentException if the category does not belong to the categorization
* @throws IllegalArgumentException if the period is outside of the specified range
* @throws NullPointerException if an input is null
*/
public final int getTrips(final Node origin, final Node destination, final Category category, final int periodIndex)
{
DurationVector time = getTimeVector(origin, destination, category);
if (time == null)
{
return 0;
}
Throw.when(periodIndex < 0 || periodIndex >= time.size() - 1, IllegalArgumentException.class,
"Period index out of range.");
FrequencyVector demand = getDemandVector(origin, destination, category);
Interpolation interpolation = getInterpolation(origin, destination, category);
try
{
return interpolation.integrate(demand.get(periodIndex), time.get(periodIndex), demand.get(periodIndex + 1), time
.get(periodIndex + 1));
}
catch (ValueException exception)
{
// should not happen as the index was checked
throw new RuntimeException("Could not get number of trips.", exception);
}
}
/**
* Adds a number of trips to given origin-destination combination, category and time period. This can only be done for data
* with stepwise interpolation.
* @param origin origin
* @param destination destination
* @param category category
* @param periodIndex index of time period
* @param trips trips to add (may be negative)
* @throws IllegalArgumentException if origin or destination is not part of the OD matrix
* @throws IllegalArgumentException if the category does not belong to the categorization
* @throws IllegalArgumentException if the period is outside of the specified range
* @throws UnsupportedOperationException if the interpolation of the data is not stepwise
* @throws NullPointerException if an input is null
*/
public final void increaseTrips(final Node origin, final Node destination, final Category category,
final int periodIndex, final int trips)
{
Interpolation interpolation = getInterpolation(origin, destination, category);
Throw.when(!interpolation.equals(Interpolation.STEPWISE), UnsupportedOperationException.class,
"Can only increase the number of trips for data with stepwise interpolation.");
DurationVector time = getTimeVector(origin, destination, category);
Throw.when(periodIndex < 0 || periodIndex >= time.size() - 1, IllegalArgumentException.class,
"Period index out of range.");
FrequencyVector demand = getDemandVector(origin, destination, category);
try
{
double additionalDemand =
trips
/ (time.get(periodIndex + 1).getInUnit(TimeUnit.HOUR) - time.get(periodIndex).getInUnit(TimeUnit.HOUR));
double[] dem = demand.getValuesInUnit(FrequencyUnit.PER_HOUR);
dem[periodIndex] += additionalDemand;
putDemandVector(origin, destination, category, new FrequencyVector(dem, FrequencyUnit.PER_HOUR,
StorageType.DENSE), time, Interpolation.STEPWISE);
}
catch (ValueException exception)
{
// should not happen as the index was checked
throw new RuntimeException("Could not get number of trips.", exception);
}
}
/**
* Calculates total number of trips over time for given origin.
* @param origin origin
* @return total number of trips over time for given origin
* @throws IllegalArgumentException if origin is not part of the OD matrix
* @throws NullPointerException if origin is null
*/
public final int originTotal(final Node origin)
{
int sum = 0;
for (Node destination : getDestinations())
{
sum += originDestinationTotal(origin, destination);
}
return sum;
}
/**
* Calculates total number of trips over time for given destination.
* @param destination destination
* @return total number of trips over time for given destination
* @throws IllegalArgumentException if destination is not part of the OD matrix
* @throws NullPointerException if destination is null
*/
public final int destinationTotal(final Node destination)
{
int sum = 0;
for (Node origin : getOrigins())
{
sum += originDestinationTotal(origin, destination);
}
return sum;
}
/**
* Calculates total number of trips over time for the complete matrix.
* @return total number of trips over time for the complete matrix
*/
public final int matrixTotal()
{
int sum = 0;
for (Node origin : getOrigins())
{
for (Node destination : getDestinations())
{
sum += originDestinationTotal(origin, destination);
}
}
return sum;
}
/**
* Calculates total number of trips over time for given origin-destination combination.
* @param origin origin
* @param destination destination
* @return total number of trips over time for given origin-destination combination
* @throws IllegalArgumentException if origin or destination is not part of the OD matrix
* @throws NullPointerException if an input is null
*/
public final int originDestinationTotal(final Node origin, final Node destination)
{
int sum = 0;
for (Category category : getCategories(origin, destination))
{
DurationVector time = getTimeVector(origin, destination, category);
FrequencyVector demand = getDemandVector(origin, destination, category);
Interpolation interpolation = getInterpolation(origin, destination, category);
for (int i = 0; i < time.size() - 1; i++)
{
try
{
sum += interpolation.integrate(demand.get(i), time.get(i), demand.get(i + 1), time.get(i + 1));
}
catch (ValueException exception)
{
// should not happen as we loop over the array length
throw new RuntimeException("Could not determine total trips over time.", exception);
}
}
}
return sum;
}
/** {@inheritDoc} */
public final String toString()
{
return "ODMatrixTrips [" + getOrigins().size() + " origins, " + getDestinations().size() + " destinations, "
+ getCategorization() + " ]";
}
}