/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2006-2025 German Aerospace Center (DLR) and others.3// This program and the accompanying materials are made available under the4// terms of the Eclipse Public License 2.0 which is available at5// https://www.eclipse.org/legal/epl-2.0/6// This Source Code may also be made available under the following Secondary7// Licenses when the conditions for such availability set forth in the Eclipse8// Public License 2.0 are satisfied: GNU General Public License, version 29// or later which is available at10// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html11// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later12/****************************************************************************/13/// @file ODMatrix.h14/// @author Daniel Krajzewicz15/// @author Michael Behrisch16/// @author Yun-Pang Floetteroed17/// @date 05. Apr. 200618///19// An O/D (origin/destination) matrix20/****************************************************************************/21#pragma once22#include <config.h>2324#include <iostream>25#include <sstream>26#include <fstream>27#include <vector>28#include <cstdlib>29#include <ctime>30#include <algorithm>31#include <set>32#include <string>33#include <utils/common/SUMOTime.h>34#include "ODCell.h"35#include "ODDistrictCont.h"36#include <utils/distribution/Distribution_Points.h>37#include <utils/importio/LineReader.h>38#include <utils/common/SUMOTime.h>39#include <utils/xml/SAXWeightsHandler.h>4041// ===========================================================================42// class declarations43// ===========================================================================44class OptionsCont;45class OutputDevice;46class SUMOSAXHandler;474849// ===========================================================================50// class definitions51// ===========================================================================52/**53* @class ODMatrix54* @brief An O/D (origin/destination) matrix55*56* This class is the internal representation of a loaded O/D-matrix. Beside57* being the storage for ODCells, the matrix also contains information about58* the numbers of loaded, discarded, and written vehicles.59*60* The matrix has a reference to the container of districts stored. This allows61* to validate added cell descriptions in means that using existing origins/62* destinations only is assured.63*64* In addition of being a storage, the matrix is also responsible for writing65* the results and contains methods for splitting the entries over time.66*/67class ODMatrix : public SAXWeightsHandler::EdgeFloatTimeLineRetriever {6869public:70/** @brief Constructor71*72* @param[in] dc The district container to obtain referenced districts from73*/74ODMatrix(const ODDistrictCont& dc, double scale);757677/// Destructor78~ODMatrix();798081/** @brief Builds a single cell from the given values, verifying them82*83* At first, the number of loaded vehicles (myNoLoaded) is incremented84* by vehicleNumber.85*86* It is checked whether both the origin and the destination exist within87* the assigned district container (myDistricts). If one of them is missing,88* an error is generated, if both, a warning, because in the later case89* the described flow may lay completely beside the processed area. In both90* cases the given number of vehicles (vehicleNumber) is added to myNoDiscarded.91*92* If the origin/destination districts are known, a cell is built using the93* given values. This cell is added to the list of known cells (myContainer).94*95* @param[in] vehicleNumber The number of vehicles to store within the cell96* @param[in] beginEnd The begin and the end of the interval the cell is valid for97* @param[in] origin The origin district to use for the cell's flows98* @param[in] destination The destination district to use for the cell's flows99* @param[in] vehicleType The vehicle type to use for the cell's flows100* @return whether the cell could be added101*/102bool add(double vehicleNumber, const std::pair<SUMOTime, SUMOTime>& beginEnd,103const std::string& origin, const std::string& destination,104const std::string& vehicleType,105const bool originIsEdge = false, const bool destinationIsEdge = false,106bool noScaling = false);107108/** @brief Adds a single vehicle with departure time109*110* If there is no existing ODCell for the given parameters one is generated111* using add(...)112*113* @param[in] id The id of the vehicle114* @param[in] depart The departure time of the vehicle115* @param[in] od The origin and destination district to use for the cell's flows116* @param[in] vehicleType The vehicle type to use for the cell's flows117* @return whether the vehicle could be added118*/119bool add(const SUMOVehicleParameter& veh, bool originIsEdge = false, bool destinationIsEdgeconst = false);120121/** @brief Helper function for flow and trip output writing the depart122* and arrival attributes123*124* @param[in] dev The stream to write the generated vehicle trips to125* @param[in] noVtype Whether vtype information shall not be written126* @param[in] cell The OD cell containing the vtype127*/128void writeDefaultAttrs(OutputDevice& dev, const bool noVtype,129const ODCell* const cell);130131/** @brief Writes the vehicles stored in the matrix assigning the sources and sinks132*133* The cells stored in myContainer are sorted, first. Then, for each time134* step to generate vehicles for, it is checked whether the topmost cell135* is valid for this time step. If so, vehicles are generated from this136* cell's description using "computeDeparts" and stored in an internal vector.137* The pointer is moved and the check is repeated until the current cell138* is not valid for the current time or no further cells exist.139*140* Then, for the current time step, the internal list of vehicles is sorted and141* all vehicles that start within this time step are written.142*143* The left fraction of vehicles to insert is saved for each O/D-dependency144* over time and the number of vehicles to generate is increased as soon145* as this value is larger than 1, decrementing it.146*147* @param[in] begin The begin time to generate vehicles for148* @param[in] end The end time to generate vehicles for149* @param[in] dev The stream to write the generated vehicle trips to150* @param[in] uniform Information whether departure times shallbe uniformly spread or random151* @param[in] differSourceSink whether source and sink shall be different edges152* @param[in] noVtype Whether vtype information shall not be written153* @param[in] prefix A prefix for the vehicle names154* @param[in] stepLog Whether processed time shall be written155* @param[in] pedestrians Writes trips for pedestrians156* @param[in] persontrips Writes trips for persontrips157*/158void write(SUMOTime begin, const SUMOTime end,159OutputDevice& dev, const bool uniform,160const bool differSourceSink, const bool noVtype,161const std::string& prefix, const bool stepLog,162bool pedestrians, bool persontrips,163const std::string& modes);164165166/** @brief Writes the flows stored in the matrix167*168* @param[in] begin The begin time to generate vehicles for169* @param[in] end The end time to generate vehicles for170* @param[in] dev The stream to write the generated vehicle trips to171* @param[in] noVtype Whether vtype information shall not be written172* @param[in] prefix A prefix for the flow names173* @param[in] asProbability Write probability to spawn per second instead of number of vehicles174* @param[in] pedestrians Writes flows for pedestrians175* @param[in] persontrips Writes flows for persontrips176*/177void writeFlows(const SUMOTime begin, const SUMOTime end,178OutputDevice& dev, const bool noVtype,179const std::string& prefix,180bool asProbability = false, bool pedestrians = false, bool persontrips = false,181const std::string& modes = "");182183184/** @brief Returns the number of loaded vehicles185*186* Returns the value of myNoLoaded187*188* @return The number of loaded vehicles189*/190double getNumLoaded() const;191192193/** @brief Returns the number of written vehicles194*195* Returns the value of myNoWritten196*197* @return The number of written vehicles198*/199double getNumWritten() const;200201202/** @brief Returns the number of discarded vehicles203*204* Returns the value of myNoDiscarded205*206* @return The number of discarded vehicles207*/208double getNumDiscarded() const;209210211/** @brief Splits the stored cells dividing them on the given time line212* @todo Describe213*/214void applyCurve(const Distribution_Points& ps);215216217/** @brief read a VISUM-matrix with the O Format218* @todo Describe219*/220void readO(LineReader& lr, double scale,221std::string vehType, bool matrixHasVehType);222223/** @brief read a VISUM-matrix with the V Format224* @todo Describe225*/226void readV(LineReader& lr, double scale,227std::string vehType, bool matrixHasVehType);228229/** @brief read a matrix in one of several formats230* @todo Describe231*/232void loadMatrix(OptionsCont& oc);233234/** @brief read SUMO routes235* @todo Describe236*/237void loadRoutes(OptionsCont& oc, SUMOSAXHandler& handler);238239/** @brief split the given timeline240* @todo Describe241*/242Distribution_Points parseTimeLine(const std::vector<std::string>& def, bool timelineDayInHours);243244const std::vector<ODCell*>& getCells() {245return myContainer;246}247248void sortByBeginTime();249250SUMOTime getBegin() const {251return myBegin;252}253254SUMOTime getEnd() const {255return myEnd;256}257258void addTazRelWeight(const std::string intervalID, const std::string& from, const std::string& to,259double val, double beg, double end);260261protected:262/**263* @struct ODVehicle264* @brief An internal representation of a single vehicle265*/266struct ODVehicle {267/// @brief The id of the vehicle268std::string id;269/// @brief The departure time of the vehicle270SUMOTime depart;271/// @brief The cell of the ODMatrix which generated the vehicle272ODCell* cell;273/// @brief The edge the vehicles shall start at274std::string from;275/// @brief The edge the vehicles shall end at276std::string to;277278};279280281/** @brief Computes the vehicle departs stored in the given cell and saves them in "into"282*283* At first, the number of vehicles to insert is computed using the284* integer value of the vehicleNumber information from the given cell.285* In the case vehicleNumber has a fraction, an additional vehicle286* may be added in the case a chosen random number is lower than this fraction.287*288* If uniform is true, the departure times of the generated vehicles289* are spread uniformly, otherwise the departure time are chosen randomly from290* the interval.291*292* The vehicle names are generated by putting the value of vehName after the293* given prefix. The value of vehName is incremented with each generated vehicle.294*295* The number of left vehicles (the fraction if no additional vehicle was296* generated) is returned.297*298* @param[in] cell The cell to use299* @param[in,out] vehName An incremented index of the generated vehicle300* @param[out] into The storage to put generated vehicles into301* @param[in] uniform Information whether departure times shallbe uniformly spread or random302* @param[in] differSourceSink whether source and sink shall be different edges303* @param[in] prefix A prefix for the vehicle names304* @return The number of left vehicles to insert305*/306double computeDeparts(ODCell* cell,307int& vehName, std::vector<ODVehicle>& into,308const bool uniform, const bool differSourceSink,309const std::string& prefix);310311312/** @brief Splits the given cell dividing it on the given time line and313* storing the results in the given container314*315* For the given cell, a list of clones is generated. The number of these316* is equal to the number of "areas" within the given distribution317* description (time line in this case) and each clone's vehicleNumber318* is equal to the given cell's vehicle number multiplied with the area's319* probability. The clones are stored in the given cell vector.320*321* @see Distribution_Points322* @param[in] ps The time line to apply323* @param[in] cell The cell to split324* @param[out] newCells The storage to put generated cells into325* @todo describe better!!!326*/327void applyCurve(const Distribution_Points& ps, ODCell* cell,328std::vector<ODCell*>& newCells);329330331private:332/** @used in the functions readV and readO333* @todo Describe334*/335std::string getNextNonCommentLine(LineReader& lr);336337/** @used in the functions readV and readO338* @todo Describe339*/340SUMOTime parseSingleTime(const std::string& time);341342/** @used in the functions readV and readO343* @todo Describe344*/345std::pair<SUMOTime, SUMOTime> readTime(LineReader& lr);346347/** @used in the functions readV and readO348* @todo Describe349*/350double readFactor(LineReader& lr, double scale);351352353private:354/// @brief The loaded cells355std::vector<ODCell*> myContainer;356357/// @brief The loaded cells indexed by origin and destination358std::map<const std::pair<const std::string, const std::string>, std::vector<ODCell*> > myShortCut;359360/// @brief The districts to retrieve sources/sinks from361const ODDistrictCont& myDistricts;362363/// @brief The missing districts already warned about364std::set<std::string> myMissingDistricts;365366/// @brief Number of loaded vehicles367double myNumLoaded;368369/// @brief Number of written vehicles370double myNumWritten;371372/// @brief Number of discarded vehicles373double myNumDiscarded;374375/// @brief parsed time bounds376SUMOTime myBegin, myEnd;377378/// @brief user-defined vType379std::string myVType;380381/// @brief the scaling factor for traffic382double myScale;383384/**385* @class cell_by_begin_comparator386* @brief Used for sorting the cells by the begin time they describe387*/388class cell_by_begin_comparator {389public:390/// @brief constructor391explicit cell_by_begin_comparator() { }392393394/** @brief Comparing operator395*396* Compares two cells by the begin of the time they describe. The sort is stabilized397* (with secondary sort keys being origin and destination) to get comparable results398* with different platforms / compilers.399*400* @param[in] p1 First cell to compare401* @param[in] p2 Second cell to compare402* @return Whether the begin time of the first cell is lower than the one of the second403*/404int operator()(ODCell* p1, ODCell* p2) const {405if (p1->begin == p2->begin) {406if (p1->origin == p2->origin) {407return p1->destination < p2->destination;408}409return p1->origin < p2->origin;410}411return p1->begin < p2->begin;412}413414};415416417/**418* @class descending_departure_comperator419* @brief Used for sorting vehicles by their departure (latest first)420*421* A reverse operator to what may be expected is used in order to allow422* prunning the sorted vector from its tail.423*/424class descending_departure_comperator {425public:426/// @brief constructor427descending_departure_comperator() { }428429430/** @brief Comparing operator431*432* Compares two vehicles by their departure time433*434* @param[in] p1 First vehicle to compare435* @param[in] p2 Second vehicle to compare436* @return Whether the departure time of the first vehicle is larger than the one of the second437*/438bool operator()(const ODVehicle& p1, const ODVehicle& p2) const {439if (p1.depart == p2.depart) {440return p1.id > p2.id;441}442return p1.depart > p2.depart;443}444445};446447private:448/** @brief invalid copy constructor */449ODMatrix(const ODMatrix& s);450451/** @brief invalid assignment operator */452ODMatrix& operator=(const ODMatrix& s) = delete;453454};455456457