LCOV - code coverage report
Current view: top level - src/od - ODMatrix.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 93.8 % 434 407
Test Date: 2026-07-05 15:55:58 Functions: 96.0 % 25 24

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2006-2026 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    ODMatrix.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Michael Behrisch
      18              : /// @author  Yun-Pang Floetteroed
      19              : /// @author  Mirko Barthauer
      20              : /// @date    05 Apr. 2006
      21              : ///
      22              : // An O/D (origin/destination) matrix
      23              : /****************************************************************************/
      24              : #include <config.h>
      25              : 
      26              : #include <iostream>
      27              : #include <algorithm>
      28              : #include <list>
      29              : #include <iterator>
      30              : #include <utils/options/OptionsCont.h>
      31              : #include <utils/common/FileHelpers.h>
      32              : #include <utils/common/StdDefs.h>
      33              : #include <utils/common/MsgHandler.h>
      34              : #include <utils/common/ToString.h>
      35              : #include <utils/common/RandHelper.h>
      36              : #include <utils/common/StringUtils.h>
      37              : #include <utils/common/StringUtils.h>
      38              : #include <utils/common/StringTokenizer.h>
      39              : #include <utils/common/SUMOTime.h>
      40              : #include <utils/iodevices/OutputDevice.h>
      41              : #include <utils/importio/LineReader.h>
      42              : #include <utils/xml/SUMOSAXHandler.h>
      43              : #include <utils/xml/XMLSubSys.h>
      44              : #include <router/RORoute.h>
      45              : #include "ODAmitranHandler.h"
      46              : #include "ODMatrix.h"
      47              : 
      48              : 
      49              : // ===========================================================================
      50              : // method definitions
      51              : // ===========================================================================
      52          247 : ODMatrix::ODMatrix(const ODDistrictCont& dc, double scale) :
      53          247 :     myDistricts(dc),
      54          247 :     myNumLoaded(0),
      55          247 :     myNumWritten(0),
      56          247 :     myNumDiscarded(0),
      57          247 :     myBegin(-1),
      58          247 :     myEnd(-1),
      59          247 :     myScale(scale)
      60          247 : {}
      61              : 
      62              : 
      63          247 : ODMatrix::~ODMatrix() {
      64         9214 :     for (ODCell* const cell : myContainer) {
      65         8967 :         delete cell;
      66              :     }
      67              :     myContainer.clear();
      68          494 : }
      69              : 
      70              : 
      71              : bool
      72          820 : ODMatrix::add(double vehicleNumber, const std::pair<SUMOTime, SUMOTime>& beginEnd,
      73              :               const std::string& origin, const std::string& destination,
      74              :               const std::string& vehicleType, const bool originIsEdge, const bool destinationIsEdge,
      75              :               bool noScaling) {
      76          820 :     if (vehicleNumber == 0) {
      77              :         return false;
      78              :     }
      79          820 :     myNumLoaded += vehicleNumber;
      80          829 :     if (!originIsEdge && !destinationIsEdge && myDistricts.get(origin) == nullptr && myDistricts.get(destination) == nullptr) {
      81           15 :         WRITE_WARNINGF(TL("Missing origin '%' and destination '%' (% vehicles)."), origin, destination, toString(vehicleNumber));
      82            5 :         myNumDiscarded += vehicleNumber;
      83              :         myMissingDistricts.insert(origin);
      84              :         myMissingDistricts.insert(destination);
      85            5 :         return false;
      86          815 :     } else if (!originIsEdge && myDistricts.get(origin) == 0) {
      87           27 :         WRITE_ERRORF(TL("Missing origin '%' (% vehicles)."), origin, toString(vehicleNumber));
      88            9 :         myNumDiscarded += vehicleNumber;
      89              :         myMissingDistricts.insert(origin);
      90            9 :         return false;
      91          806 :     } else if (!destinationIsEdge && myDistricts.get(destination) == 0) {
      92           27 :         WRITE_ERRORF(TL("Missing destination '%' (% vehicles)."), destination, toString(vehicleNumber));
      93            9 :         myNumDiscarded += vehicleNumber;
      94              :         myMissingDistricts.insert(destination);
      95            9 :         return false;
      96              :     }
      97         1581 :     if (!originIsEdge && myDistricts.get(origin)->sourceNumber() == 0) {
      98           36 :         WRITE_ERRORF(TL("District '%' has no source."), origin);
      99           12 :         myNumDiscarded += vehicleNumber;
     100           12 :         return false;
     101         1557 :     } else if (!destinationIsEdge && myDistricts.get(destination)->sinkNumber() == 0) {
     102           36 :         WRITE_ERRORF(TL("District '%' has no sink."), destination);
     103           12 :         myNumDiscarded += vehicleNumber;
     104           12 :         return false;
     105              :     }
     106          773 :     ODCell* cell = new ODCell();
     107          773 :     cell->begin = beginEnd.first;
     108          773 :     cell->end = beginEnd.second;
     109          773 :     cell->origin = origin;
     110          773 :     cell->destination = destination;
     111          773 :     cell->vehicleType = vehicleType;
     112          773 :     cell->vehicleNumber = vehicleNumber * (noScaling ? 1 : myScale);
     113          773 :     cell->originIsEdge = originIsEdge;
     114          773 :     cell->destinationIsEdge = destinationIsEdge;
     115          773 :     myContainer.push_back(cell);
     116          773 :     if (myBegin == -1 || cell->begin < myBegin) {
     117          208 :         myBegin = cell->begin;
     118              :     }
     119          773 :     if (cell->end > myEnd) {
     120          208 :         myEnd = cell->end;
     121              :     }
     122              :     return true;
     123              : }
     124              : 
     125              : 
     126              : bool
     127         1510 : ODMatrix::add(const SUMOVehicleParameter& veh, bool originIsEdge, bool destinationIsEdge) {
     128              :     const std::string fromTaz = veh.fromTaz;
     129              :     const std::string toTaz = veh.toTaz;
     130              :     if (myMissingDistricts.count(fromTaz) > 0 || myMissingDistricts.count(toTaz) > 0) {
     131            0 :         myNumLoaded += 1.;
     132            0 :         myNumDiscarded += 1.;
     133            0 :         return false;
     134              :     }
     135              :     // we start looking from the end because there is a high probability that the input is sorted by time
     136         3020 :     std::vector<ODCell*>& odList = myShortCut[std::make_pair(fromTaz, toTaz)];
     137         1510 :     ODCell* cell = nullptr;
     138         1510 :     for (std::vector<ODCell*>::const_reverse_iterator c = odList.rbegin(); c != odList.rend(); ++c) {
     139         1474 :         if ((*c)->begin <= veh.depart && (*c)->end > veh.depart && (*c)->vehicleType == veh.vtypeid) {
     140         1474 :             cell = *c;
     141         1474 :             break;
     142              :         }
     143              :     }
     144         1510 :     if (cell == nullptr) {
     145           36 :         const SUMOTime interval = string2time(OptionsCont::getOptions().getString("aggregation-interval"));
     146           36 :         const int intervalIdx = (int)(veh.depart / interval);
     147              :         // single vehicles are already scaled
     148           36 :         if (add(1., std::make_pair(intervalIdx * interval, (intervalIdx + 1) * interval),
     149           36 :                 fromTaz, toTaz, veh.vtypeid, originIsEdge, destinationIsEdge, true)) {
     150           35 :             cell = myContainer.back();
     151           35 :             odList.push_back(cell);
     152              :         } else {
     153              :             return false;
     154              :         }
     155              :     } else {
     156         1474 :         myNumLoaded += 1.;
     157         1474 :         cell->vehicleNumber += 1.;
     158              :     }
     159         1509 :     cell->departures[veh.depart].push_back(veh);
     160              :     return true;
     161              : }
     162              : 
     163              : 
     164              : double
     165         6826 : ODMatrix::computeDeparts(ODCell* cell,
     166              :                          int& vehName, std::vector<ODVehicle>& into,
     167              :                          const bool uniform, const bool differSourceSink,
     168              :                          const std::string& prefix) {
     169         6826 :     int vehicles2insert = (int) cell->vehicleNumber;
     170              :     // compute whether the fraction forces an additional vehicle insertion
     171         6826 :     if (RandHelper::rand() < cell->vehicleNumber - (double)vehicles2insert) {
     172         2128 :         vehicles2insert++;
     173              :     }
     174         6826 :     if (vehicles2insert == 0) {
     175              :         return cell->vehicleNumber;
     176              :     }
     177              : 
     178         3098 :     const double offset = (double)(cell->end - cell->begin) / (double) vehicles2insert / (double) 2.;
     179        18986 :     for (int i = 0; i < vehicles2insert; ++i) {
     180              :         ODVehicle veh;
     181        15888 :         veh.id = prefix + toString(vehName++);
     182              : 
     183        15888 :         if (uniform) {
     184         1856 :             veh.depart = cell->begin + (SUMOTime)(offset + ((double)(cell->end - cell->begin) * (double) i / (double) vehicles2insert));
     185              :         } else {
     186        14032 :             veh.depart = (SUMOTime)RandHelper::rand(cell->begin, cell->end);
     187              :         }
     188        47464 :         const bool canDiffer = myDistricts.get(cell->origin)->sourceNumber() > 1 || myDistricts.get(cell->destination)->sinkNumber() > 1;
     189              :         do {
     190        15963 :             veh.from = myDistricts.getRandomSourceFromDistrict(cell->origin);
     191        15963 :             veh.to = myDistricts.getRandomSinkFromDistrict(cell->destination);
     192        15963 :         } while (canDiffer && differSourceSink && (veh.to == veh.from));
     193        15888 :         if (!canDiffer && differSourceSink && (veh.to == veh.from)) {
     194           30 :             WRITE_WARNINGF(TL("Cannot find different source and sink edge for origin '%' and destination '%'."), cell->origin, cell->destination);
     195              :         }
     196        15888 :         veh.cell = cell;
     197        15888 :         into.push_back(veh);
     198        15888 :     }
     199         3098 :     return cell->vehicleNumber - vehicles2insert;
     200              : }
     201              : 
     202              : 
     203              : void
     204        16886 : ODMatrix::writeDefaultAttrs(OutputDevice& dev, const bool noVtype,
     205              :                             const ODCell* const cell) {
     206        16886 :     const OptionsCont& oc = OptionsCont::getOptions();
     207        16886 :     if (!noVtype && cell->vehicleType != "") {
     208         1942 :         dev.writeAttr(SUMO_ATTR_TYPE, cell->vehicleType);
     209              :     }
     210        16886 :     dev.writeAttr(SUMO_ATTR_FROM_TAZ, cell->origin).writeAttr(SUMO_ATTR_TO_TAZ, cell->destination);
     211        50658 :     if (oc.isSet("departlane") && oc.getString("departlane") != "default") {
     212        33772 :         dev.writeAttr(SUMO_ATTR_DEPARTLANE, oc.getString("departlane"));
     213              :     }
     214        33772 :     if (oc.isSet("departpos")) {
     215            2 :         dev.writeAttr(SUMO_ATTR_DEPARTPOS, oc.getString("departpos"));
     216              :     }
     217        50658 :     if (oc.isSet("departspeed") && oc.getString("departspeed") != "default") {
     218        33772 :         dev.writeAttr(SUMO_ATTR_DEPARTSPEED, oc.getString("departspeed"));
     219              :     }
     220        33772 :     if (oc.isSet("arrivallane")) {
     221            2 :         dev.writeAttr(SUMO_ATTR_ARRIVALLANE, oc.getString("arrivallane"));
     222              :     }
     223        33772 :     if (oc.isSet("arrivalpos")) {
     224            2 :         dev.writeAttr(SUMO_ATTR_ARRIVALPOS, oc.getString("arrivalpos"));
     225              :     }
     226        33772 :     if (oc.isSet("arrivalspeed")) {
     227            2 :         dev.writeAttr(SUMO_ATTR_ARRIVALSPEED, oc.getString("arrivalspeed"));
     228              :     }
     229        16886 : }
     230              : 
     231              : 
     232              : void
     233           86 : ODMatrix::write(SUMOTime begin, const SUMOTime end,
     234              :                 OutputDevice& dev, const bool uniform,
     235              :                 const bool differSourceSink, const bool noVtype,
     236              :                 const std::string& prefix, const bool stepLog,
     237              :                 bool pedestrians, bool persontrips,
     238              :                 const std::string& modes) {
     239           86 :     if (myContainer.size() == 0) {
     240            0 :         return;
     241              :     }
     242              :     std::map<std::pair<std::string, std::string>, double> fractionLeft;
     243           86 :     int vehName = 0;
     244           86 :     sortByBeginTime();
     245              :     // recheck begin time
     246           86 :     begin = MAX2(begin, myContainer.front()->begin);
     247              :     std::vector<ODCell*>::iterator next = myContainer.begin();
     248              :     std::vector<ODVehicle> vehicles;
     249           86 :     SUMOTime lastOut = -DELTA_T;
     250              : 
     251           86 :     const OptionsCont& oc = OptionsCont::getOptions();
     252           88 :     std::string personDepartPos = oc.isSet("departpos") ? oc.getString("departpos") : "random";
     253           88 :     std::string personArrivalPos = oc.isSet("arrivalpos") ? oc.getString("arrivalpos") : "random";
     254          171 :     SumoXMLAttr fromAttr = oc.getBool("junctions") ? SUMO_ATTR_FROM_JUNCTION : SUMO_ATTR_FROM;
     255          171 :     SumoXMLAttr toAttr = oc.getBool("junctions") ? SUMO_ATTR_TO_JUNCTION : SUMO_ATTR_TO;
     256          172 :     const std::string vType = oc.isSet("vtype") ? oc.getString("vtype") : "";
     257              : 
     258              :     // go through the time steps
     259        16061 :     for (SUMOTime t = begin; t < end;) {
     260        16060 :         if (stepLog && t - lastOut >= DELTA_T) {
     261            0 :             std::cout << "Parsing time " + time2string(t) << '\r';
     262              :             lastOut = t;
     263              :         }
     264              :         // recheck whether a new cell got valid
     265              :         bool changed = false;
     266        22886 :         while (next != myContainer.end() && (*next)->begin <= t && (*next)->end > t) {
     267         6826 :             std::pair<std::string, std::string> odID = std::make_pair((*next)->origin, (*next)->destination);
     268              :             // check whether the current cell must be extended by the last fraction
     269         6826 :             if (fractionLeft.find(odID) != fractionLeft.end()) {
     270         6210 :                 (*next)->vehicleNumber += fractionLeft[odID];
     271         6210 :                 fractionLeft[odID] = 0;
     272              :             }
     273              :             // get the new departures (into tmp)
     274         6826 :             const int oldSize = (int)vehicles.size();
     275         6826 :             const double fraction = computeDeparts(*next, vehName, vehicles, uniform, differSourceSink, prefix);
     276         6826 :             if (oldSize != (int)vehicles.size()) {
     277              :                 changed = true;
     278              :             }
     279         6826 :             if (fraction != 0) {
     280         6472 :                 fractionLeft[odID] = fraction;
     281              :             }
     282              :             ++next;
     283              :         }
     284        16060 :         if (changed) {
     285          192 :             sort(vehicles.begin(), vehicles.end(), descending_departure_comperator());
     286              :         }
     287              : 
     288        31875 :         for (std::vector<ODVehicle>::reverse_iterator i = vehicles.rbegin(); i != vehicles.rend() && (*i).depart == t; ++i) {
     289        15815 :             if (t >= begin) {
     290        15793 :                 myNumWritten++;
     291        15793 :                 if (pedestrians) {
     292          400 :                     dev.openTag(SUMO_TAG_PERSON).writeAttr(SUMO_ATTR_ID, (*i).id).writeAttr(SUMO_ATTR_DEPART, time2string(t));
     293          400 :                     dev.writeAttr(SUMO_ATTR_DEPARTPOS, personDepartPos);
     294          400 :                     if (!noVtype && vType.size() > 0) {
     295            0 :                         dev.writeAttr(SUMO_ATTR_TYPE, vType);
     296              :                     }
     297          400 :                     dev.openTag(SUMO_TAG_WALK);
     298          400 :                     dev.writeAttr(fromAttr, (*i).from);
     299          400 :                     dev.writeAttr(toAttr, (*i).to);
     300          400 :                     dev.writeAttr(SUMO_ATTR_FROM_TAZ, (*i).cell->origin).writeAttr(SUMO_ATTR_TO_TAZ, (*i).cell->destination);
     301          400 :                     dev.writeAttr(SUMO_ATTR_ARRIVALPOS, personArrivalPos);
     302          400 :                     dev.closeTag();
     303          800 :                     dev.closeTag();
     304        15393 :                 } else if (persontrips) {
     305          600 :                     dev.openTag(SUMO_TAG_PERSON).writeAttr(SUMO_ATTR_ID, (*i).id).writeAttr(SUMO_ATTR_DEPART, time2string(t));
     306          600 :                     dev.writeAttr(SUMO_ATTR_DEPARTPOS, personDepartPos);
     307          600 :                     dev.openTag(SUMO_TAG_PERSONTRIP);
     308          600 :                     dev.writeAttr(fromAttr, (*i).from);
     309          600 :                     dev.writeAttr(toAttr, (*i).to);
     310          600 :                     dev.writeAttr(SUMO_ATTR_FROM_TAZ, (*i).cell->origin).writeAttr(SUMO_ATTR_TO_TAZ, (*i).cell->destination);
     311          600 :                     dev.writeAttr(SUMO_ATTR_ARRIVALPOS, personArrivalPos);
     312          600 :                     if (modes != "") {
     313          100 :                         dev.writeAttr(SUMO_ATTR_MODES, modes);
     314              :                     }
     315          600 :                     dev.closeTag();
     316         1200 :                     dev.closeTag();
     317              :                 } else {
     318        14793 :                     dev.openTag(SUMO_TAG_TRIP).writeAttr(SUMO_ATTR_ID, (*i).id).writeAttr(SUMO_ATTR_DEPART, time2string(t));
     319        14793 :                     dev.writeAttr(fromAttr, (*i).from);
     320        14793 :                     dev.writeAttr(toAttr, (*i).to);
     321        14793 :                     writeDefaultAttrs(dev, noVtype, i->cell);
     322        29586 :                     dev.closeTag();
     323              :                 }
     324              :             }
     325              :         }
     326        31875 :         while (vehicles.size() != 0 && vehicles.back().depart == t) {
     327              :             vehicles.pop_back();
     328              :         }
     329        16060 :         if (!vehicles.empty()) {
     330        15810 :             t = vehicles.back().depart;
     331              :         }
     332        16060 :         if (next != myContainer.end() && (t > (*next)->begin || vehicles.empty())) {
     333              :             t = (*next)->begin;
     334              :         }
     335        32035 :         if (next == myContainer.end() && vehicles.empty()) {
     336              :             break;
     337              :         }
     338              :     }
     339           86 : }
     340              : 
     341              : 
     342              : void
     343           33 : ODMatrix::writeFlows(const SUMOTime begin, const SUMOTime end,
     344              :                      OutputDevice& dev, bool noVtype,
     345              :                      const std::string& prefix,
     346              :                      bool asProbability,
     347              :                      bool asPoisson,
     348              :                      bool pedestrians, bool persontrips,
     349              :                      const std::string& modes) {
     350           33 :     if (myContainer.size() == 0) {
     351              :         return;
     352              :     }
     353              :     int flowName = 0;
     354           33 :     sortByBeginTime();
     355              :     // recheck begin time
     356          209 :     for (std::vector<ODCell*>::const_iterator i = myContainer.begin(); i != myContainer.end(); ++i) {
     357          176 :         const ODCell* const c = *i;
     358          176 :         if (c->end > begin && c->begin < end) {
     359          176 :             const double probability = float(c->vehicleNumber) / STEPS2TIME(c->end - c->begin);
     360          176 :             if (probability <= 0) {
     361           72 :                 continue;
     362              :             }
     363              :             //Person flows
     364          104 :             if (pedestrians) {
     365            4 :                 dev.openTag(SUMO_TAG_PERSONFLOW).writeAttr(SUMO_ATTR_ID, prefix + toString(flowName++));
     366            4 :                 dev.writeAttr(SUMO_ATTR_BEGIN, time2string(c->begin)).writeAttr(SUMO_ATTR_END, time2string(c->end));
     367            4 :                 if (asPoisson) {
     368            0 :                     dev.writeAttr(SUMO_ATTR_PERIOD, "exp(" + StringUtils::adjustDecimalValue(probability, 10) + ")");
     369            4 :                 } else if (!asProbability) {
     370            4 :                     dev.writeAttr(SUMO_ATTR_NUMBER, int(c->vehicleNumber));
     371              :                 } else {
     372            0 :                     if (probability > 1) {
     373            0 :                         WRITE_WARNINGF(TL("Flow density of % vehicles per second, cannot be represented with a simple probability. Falling back to even spacing."), toString(probability));
     374            0 :                         dev.writeAttr(SUMO_ATTR_NUMBER, int(c->vehicleNumber));
     375              :                     } else {
     376            0 :                         dev.setPrecision(6);
     377            0 :                         dev.writeAttr(SUMO_ATTR_PROB, probability);
     378            0 :                         dev.setPrecision();
     379              :                     }
     380              :                 }
     381            4 :                 dev.openTag(SUMO_TAG_WALK);
     382            4 :                 dev.writeAttr(SUMO_ATTR_FROM_TAZ, c->origin).writeAttr(SUMO_ATTR_TO_TAZ, c->destination);
     383            4 :                 dev.writeAttr(SUMO_ATTR_ARRIVALPOS, "random");
     384            4 :                 dev.closeTag();
     385            8 :                 dev.closeTag();
     386          100 :             } else if (persontrips) {
     387           14 :                 dev.openTag(SUMO_TAG_PERSONFLOW).writeAttr(SUMO_ATTR_ID, prefix + toString(flowName++));
     388           14 :                 dev.writeAttr(SUMO_ATTR_BEGIN, time2string(c->begin)).writeAttr(SUMO_ATTR_END, time2string(c->end));
     389           14 :                 if (asPoisson) {
     390            0 :                     dev.writeAttr(SUMO_ATTR_PERIOD, "exp(" + StringUtils::adjustDecimalValue(probability, 10) + ")");
     391           14 :                 } else if (!asProbability) {
     392           12 :                     dev.writeAttr(SUMO_ATTR_NUMBER, int(c->vehicleNumber));
     393              :                 } else {
     394            2 :                     if (probability > 1) {
     395            2 :                         WRITE_WARNINGF(TL("Flow density of % vehicles per second, cannot be represented with a simple probability. Falling back to even spacing."), toString(probability));
     396            1 :                         dev.writeAttr(SUMO_ATTR_NUMBER, int(c->vehicleNumber));
     397              :                     } else {
     398            1 :                         dev.setPrecision(6);
     399            1 :                         dev.writeAttr(SUMO_ATTR_PROB, probability);
     400            1 :                         dev.setPrecision();
     401              :                     }
     402              :                 }
     403           14 :                 dev.openTag(SUMO_TAG_PERSONTRIP);
     404           14 :                 dev.writeAttr(SUMO_ATTR_FROM_TAZ, c->origin).writeAttr(SUMO_ATTR_TO_TAZ, c->destination);
     405           14 :                 dev.writeAttr(SUMO_ATTR_ARRIVALPOS, "random");
     406           14 :                 if (modes != "") {
     407            0 :                     dev.writeAttr(SUMO_ATTR_MODES, modes);
     408              :                 }
     409           14 :                 dev.closeTag();
     410           28 :                 dev.closeTag();
     411              :             } else {
     412              :                 // Normal flow output
     413           86 :                 dev.openTag(SUMO_TAG_FLOW).writeAttr(SUMO_ATTR_ID, prefix + toString(flowName++));
     414           86 :                 dev.writeAttr(SUMO_ATTR_BEGIN, time2string(c->begin));
     415           86 :                 dev.writeAttr(SUMO_ATTR_END, time2string(c->end));
     416           86 :                 if (asPoisson) {
     417            3 :                     dev.writeAttr(SUMO_ATTR_PERIOD, "exp(" + StringUtils::adjustDecimalValue(probability, 10) + ")");
     418           85 :                 } else if (!asProbability) {
     419           10 :                     dev.writeAttr(SUMO_ATTR_NUMBER, int(c->vehicleNumber));
     420              :                 } else {
     421           75 :                     if (probability > 1) {
     422            2 :                         WRITE_WARNINGF(TL("Flow density of % vehicles per second, cannot be represented with a simple probability. Falling back to even spacing."), toString(probability));
     423            1 :                         dev.writeAttr(SUMO_ATTR_NUMBER, int(c->vehicleNumber));
     424              :                     } else {
     425           74 :                         dev.setPrecision(6);
     426           74 :                         dev.writeAttr(SUMO_ATTR_PROB, probability);
     427           74 :                         dev.setPrecision();
     428              :                     }
     429              :                 }
     430           86 :                 writeDefaultAttrs(dev, noVtype, *i);
     431          172 :                 dev.closeTag();
     432              :             }
     433              :         }
     434              :     }
     435              : }
     436              : 
     437              : 
     438              : std::string
     439          931 : ODMatrix::getNextNonCommentLine(LineReader& lr) {
     440         2195 :     while (lr.good() && lr.hasMore()) {
     441         2194 :         const std::string line = lr.readLine();
     442         2194 :         if (line[0] != '*') {
     443         1860 :             return StringUtils::prune(line);
     444              :         }
     445              :     }
     446            2 :     throw ProcessError(TLF("End of file while reading %.", lr.getFileName()));
     447              : }
     448              : 
     449              : 
     450              : SUMOTime
     451          350 : ODMatrix::parseSingleTime(const std::string& time) {
     452          350 :     if (time.find('.') == std::string::npos) {
     453           16 :         throw NumberFormatException("no separator");
     454              :     }
     455          342 :     const std::string hours = time.substr(0, time.find('.'));
     456          342 :     const std::string minutes = time.substr(time.find('.') + 1);
     457          684 :     return TIME2STEPS(StringUtils::toInt(hours) * 3600 + StringUtils::toInt(minutes) * 60);
     458              : }
     459              : 
     460              : 
     461              : std::pair<SUMOTime, SUMOTime>
     462          179 : ODMatrix::readTime(LineReader& lr) {
     463          179 :     std::string line = getNextNonCommentLine(lr);
     464              :     try {
     465          358 :         StringTokenizer st(line, StringTokenizer::WHITECHARS);
     466          179 :         const SUMOTime begin = parseSingleTime(st.next());
     467          175 :         const SUMOTime end = parseSingleTime(st.next());
     468          167 :         if (begin >= end) {
     469           16 :             throw ProcessError("Matrix begin time " + time2string(begin) + " is larger than end time " + time2string(end) + ".");
     470              :         }
     471          163 :         return std::make_pair(begin, end);
     472          195 :     } catch (OutOfBoundsException&) {
     473           12 :         throw ProcessError(TLF("Broken period definition '%'.", line));
     474           12 :     } catch (NumberFormatException& e) {
     475           24 :         throw ProcessError("Broken period definition '" + line + "' (" + e.what() + ").");
     476            8 :     }
     477              : }
     478              : 
     479              : 
     480              : double
     481          163 : ODMatrix::readFactor(LineReader& lr, double scale) {
     482          163 :     std::string line = getNextNonCommentLine(lr);
     483              :     double factor = -1;
     484              :     try {
     485          163 :         factor = StringUtils::toDouble(line) * scale;
     486            6 :     } catch (NumberFormatException&) {
     487           18 :         throw ProcessError(TLF("Broken factor: '%'.", line));
     488            6 :     }
     489          157 :     return factor;
     490              : }
     491              : 
     492              : void
     493           66 : ODMatrix::readV(LineReader& lr, double scale,
     494              :                 std::string vehType, bool matrixHasVehType) {
     495          198 :     PROGRESS_BEGIN_MESSAGE("Reading matrix '" + lr.getFileName() + "' stored as VMR");
     496              :     // parse first defs
     497              :     std::string line;
     498           66 :     if (matrixHasVehType) {
     499           37 :         line = getNextNonCommentLine(lr);
     500           37 :         if (vehType == "") {
     501           74 :             vehType = StringUtils::prune(line);
     502              :         }
     503              :     }
     504              : 
     505           66 :     const std::pair<SUMOTime, SUMOTime> beginEnd = readTime(lr);
     506           58 :     const double factor = readFactor(lr, scale);
     507              : 
     508              :     // districts
     509           56 :     line = getNextNonCommentLine(lr);
     510           78 :     const int numDistricts = StringUtils::toInt(StringUtils::prune(line));
     511              :     // parse district names (normally ints)
     512              :     std::vector<std::string> names;
     513          134 :     while ((int)names.size() != numDistricts && lr.hasMore()) {
     514           78 :         line = getNextNonCommentLine(lr);
     515          156 :         StringTokenizer st2(line, StringTokenizer::WHITECHARS);
     516          392 :         while (st2.hasNext()) {
     517          628 :             names.push_back(st2.next());
     518              :         }
     519           78 :     }
     520           56 :     if (!lr.hasMore()) {
     521            6 :         throw ProcessError(TLF("Missing line with % district names.", toString(numDistricts)));
     522              :     }
     523              : 
     524              :     // parse the cells
     525          204 :     for (std::vector<std::string>::iterator si = names.begin(); si != names.end(); ++si) {
     526              :         std::vector<std::string>::iterator di = names.begin();
     527              :         do {
     528              :             try {
     529          369 :                 line = getNextNonCommentLine(lr);
     530            1 :             } catch (ProcessError&) {
     531            3 :                 throw ProcessError(TLF("Missing line for district %.", (*si)));
     532            1 :             }
     533          184 :             if (line.length() == 0) {
     534            1 :                 continue;
     535              :             }
     536              :             try {
     537          366 :                 StringTokenizer st2(line, StringTokenizer::WHITECHARS);
     538          951 :                 while (st2.hasNext()) {
     539              :                     assert(di != names.end());
     540          776 :                     double vehNumber = StringUtils::toDouble(st2.next()) * factor;
     541          768 :                     if (vehNumber != 0) {
     542          556 :                         add(vehNumber, beginEnd, *si, *di, vehType);
     543              :                     }
     544          768 :                     if (di == names.end()) {
     545            0 :                         throw ProcessError(TL("More entries than districts found."));
     546              :                     }
     547              :                     ++di;
     548              :                 }
     549          191 :             } catch (NumberFormatException&) {
     550           24 :                 throw ProcessError(TLF("Not numeric vehicle number in line '%'.", line));
     551            8 :             }
     552          175 :             if (!lr.hasMore()) {
     553              :                 break;
     554              :             }
     555          137 :         } while (di != names.end());
     556              :     }
     557           44 :     PROGRESS_DONE_MESSAGE();
     558          100 : }
     559              : 
     560              : 
     561              : void
     562          113 : ODMatrix::readO(LineReader& lr, double scale,
     563              :                 std::string vehType, bool matrixHasVehType) {
     564          339 :     PROGRESS_BEGIN_MESSAGE("Reading matrix '" + lr.getFileName() + "' stored as OR");
     565              :     // parse first defs
     566              :     std::string line;
     567          113 :     if (matrixHasVehType) {
     568           11 :         line = getNextNonCommentLine(lr);
     569           11 :         int type = StringUtils::toInt(StringUtils::prune(line));
     570           11 :         if (vehType == "") {
     571           22 :             vehType = toString(type);
     572              :         }
     573              :     }
     574              : 
     575          113 :     const std::pair<SUMOTime, SUMOTime> beginEnd = readTime(lr);
     576          105 :     const double factor = readFactor(lr, scale);
     577              : 
     578              :     // parse the cells
     579          321 :     while (lr.hasMore()) {
     580          444 :         line = getNextNonCommentLine(lr);
     581          222 :         if (line.length() == 0) {
     582           26 :             continue;
     583              :         }
     584          406 :         StringTokenizer st2(line, StringTokenizer::WHITECHARS);
     585          196 :         if (st2.size() == 0) {
     586              :             continue;
     587              :         }
     588              :         try {
     589          196 :             std::string sourceD = st2.next();
     590          196 :             std::string destD = st2.next();
     591          198 :             double vehNumber = StringUtils::toDouble(st2.next()) * factor;
     592          194 :             if (vehNumber != 0) {
     593          194 :                 add(vehNumber, beginEnd, sourceD, destD, vehType);
     594              :             }
     595            2 :         } catch (OutOfBoundsException&) {
     596            0 :             throw ProcessError(TLF("Missing at least one information in line '%'.", line));
     597            2 :         } catch (NumberFormatException&) {
     598            6 :             throw ProcessError(TLF("Not numeric vehicle number in line '%'.", line));
     599            2 :         }
     600          196 :     }
     601           99 :     PROGRESS_DONE_MESSAGE();
     602           99 : }
     603              : 
     604              : 
     605              : 
     606              : double
     607          468 : ODMatrix::getNumLoaded() const {
     608          468 :     return myNumLoaded;
     609              : }
     610              : 
     611              : 
     612              : double
     613          108 : ODMatrix::getNumWritten() const {
     614          108 :     return myNumWritten;
     615              : }
     616              : 
     617              : 
     618              : double
     619          269 : ODMatrix::getNumDiscarded() const {
     620          269 :     return myNumDiscarded;
     621              : }
     622              : 
     623              : 
     624              : void
     625          362 : ODMatrix::applyCurve(const Distribution_Points& ps, ODCell* cell, std::vector<ODCell*>& newCells) {
     626              :     const std::vector<double>& times = ps.getVals();
     627         8918 :     for (int i = 0; i < (int)times.size() - 1; ++i) {
     628         8556 :         ODCell* ncell = new ODCell();
     629         8556 :         ncell->begin = TIME2STEPS(times[i]);
     630         8556 :         ncell->end = TIME2STEPS(times[i + 1]);
     631         8556 :         ncell->origin = cell->origin;
     632         8556 :         ncell->destination = cell->destination;
     633         8556 :         ncell->vehicleType = cell->vehicleType;
     634         8556 :         ncell->vehicleNumber = cell->vehicleNumber * ps.getProbs()[i] / ps.getOverallProb();
     635         8556 :         newCells.push_back(ncell);
     636              :     }
     637          362 : }
     638              : 
     639              : 
     640              : void
     641           19 : ODMatrix::applyCurve(const Distribution_Points& ps) {
     642           19 :     std::vector<ODCell*> oldCells = myContainer;
     643              :     myContainer.clear();
     644          381 :     for (std::vector<ODCell*>::iterator i = oldCells.begin(); i != oldCells.end(); ++i) {
     645              :         std::vector<ODCell*> newCells;
     646          362 :         applyCurve(ps, *i, newCells);
     647              :         copy(newCells.begin(), newCells.end(), back_inserter(myContainer));
     648          362 :         delete *i;
     649          362 :     }
     650           19 : }
     651              : 
     652              : 
     653              : void
     654          247 : ODMatrix::loadMatrix(OptionsCont& oc) {
     655          494 :     std::vector<std::string> files = oc.getStringVector("od-matrix-files");
     656          390 :     for (std::vector<std::string>::iterator i = files.begin(); i != files.end(); ++i) {
     657          181 :         LineReader lr(*i);
     658          181 :         if (!lr.good()) {
     659            6 :             throw ProcessError(TLF("Could not open '%'.", (*i)));
     660              :         }
     661          179 :         std::string type = lr.readLine();
     662              :         // get the type only
     663          179 :         if (type.find(';') != std::string::npos) {
     664          252 :             type = type.substr(0, type.find(';'));
     665              :         }
     666              :         // parse type-dependant
     667          179 :         if (type.length() > 1 && type[1] == 'V') {
     668              :             // process ptv's 'V'-matrices
     669           66 :             if (type.find('N') != std::string::npos) {
     670            0 :                 throw ProcessError(TLF("'%' does not contain the needed information about the time described.", *i));
     671              :             }
     672          110 :             readV(lr, 1, oc.getString("vtype"), type.find('M') != std::string::npos);
     673          113 :         } else if (type.length() > 1 && type[1] == 'O') {
     674              :             // process ptv's 'O'-matrices
     675          113 :             if (type.find('N') != std::string::npos) {
     676            0 :                 throw ProcessError(TLF("'%' does not contain the needed information about the time described.", *i));
     677              :             }
     678          248 :             readO(lr, 1, oc.getString("vtype"), type.find('M') != std::string::npos);
     679              :         } else {
     680            0 :             throw ProcessError("'" + *i + "' uses an unknown matrix type '" + type + "'.");
     681              :         }
     682          181 :     }
     683          418 :     std::vector<std::string> amitranFiles = oc.getStringVector("od-amitran-files");
     684          236 :     for (std::vector<std::string>::iterator i = amitranFiles.begin(); i != amitranFiles.end(); ++i) {
     685           54 :         if (!FileHelpers::isReadable(*i)) {
     686            0 :             throw ProcessError(TLF("Could not access matrix file '%' to load.", *i));
     687              :         }
     688           81 :         PROGRESS_BEGIN_MESSAGE("Loading matrix in Amitran format from '" + *i + "'");
     689           27 :         ODAmitranHandler handler(*this, *i);
     690           27 :         if (!XMLSubSys::runParser(handler, *i)) {
     691            4 :             PROGRESS_FAILED_MESSAGE();
     692              :         } else {
     693           23 :             PROGRESS_DONE_MESSAGE();
     694              :         }
     695           27 :     }
     696          209 :     myVType = oc.getString("vtype");
     697          425 :     for (std::string file : oc.getStringVector("tazrelation-files")) {
     698           14 :         if (!FileHelpers::isReadable(file)) {
     699            0 :             throw ProcessError(TLF("Could not access matrix file '%' to load.", file));
     700              :         }
     701           21 :         PROGRESS_BEGIN_MESSAGE("Loading matrix in tazRelation format from '" + file + "'");
     702              : 
     703              :         std::vector<SAXWeightsHandler::ToRetrieveDefinition*> retrieverDefs;
     704            7 :         retrieverDefs.push_back(new SAXWeightsHandler::ToRetrieveDefinition(oc.getString("tazrelation-attribute"), true, *this));
     705            7 :         SAXWeightsHandler handler(retrieverDefs, "");
     706            7 :         if (!XMLSubSys::runParser(handler, file)) {
     707            0 :             PROGRESS_FAILED_MESSAGE();
     708              :         } else {
     709            7 :             PROGRESS_DONE_MESSAGE();
     710              :         }
     711            7 :     }
     712          247 : }
     713              : 
     714              : void
     715            7 : ODMatrix::addTazRelWeight(const std::string intervalID, const std::string& from, const std::string& to,
     716              :                           double val, double beg, double end) {
     717            8 :     add(val, std::make_pair(TIME2STEPS(beg), TIME2STEPS(end)), from, to, myVType == "" ? intervalID : myVType);
     718            7 : }
     719              : 
     720              : 
     721              : void
     722           86 : ODMatrix::loadRoutes(OptionsCont& oc, SUMOSAXHandler& handler) {
     723          172 :     std::vector<std::string> routeFiles = oc.getStringVector("route-files");
     724          119 :     for (std::vector<std::string>::iterator i = routeFiles.begin(); i != routeFiles.end(); ++i) {
     725           66 :         if (!FileHelpers::isReadable(*i)) {
     726            0 :             throw ProcessError(TLF("Could not access route file '%' to load.", *i));
     727              :         }
     728           99 :         PROGRESS_BEGIN_MESSAGE("Loading routes and trips from '" + *i + "'");
     729           33 :         if (!XMLSubSys::runParser(handler, *i)) {
     730            1 :             PROGRESS_FAILED_MESSAGE();
     731              :         } else {
     732           32 :             PROGRESS_DONE_MESSAGE();
     733              :         }
     734              :     }
     735           86 : }
     736              : 
     737              : 
     738              : Distribution_Points
     739           19 : ODMatrix::parseTimeLine(const std::vector<std::string>& def, bool timelineDayInHours) {
     740           19 :     Distribution_Points result("N/A");
     741           19 :     if (timelineDayInHours) {
     742           13 :         if (def.size() != 24) {
     743            0 :             throw ProcessError(TLF("Assuming 24 entries for a day timeline, but got %.", toString(def.size())));
     744              :         }
     745          325 :         for (int chour = 0; chour < 24; ++chour) {
     746          312 :             result.add(chour * 3600., StringUtils::toDouble(def[chour]));
     747              :         }
     748           13 :         result.add(24 * 3600., 0.); // dummy value to finish the last interval
     749              :     } else {
     750           24 :         for (int i = 0; i < (int)def.size(); i++) {
     751           54 :             StringTokenizer st2(def[i], ":");
     752           18 :             if (st2.size() != 2) {
     753            0 :                 throw ProcessError(TLF("Broken time line definition: missing a value in '%'.", def[i]));
     754              :             }
     755           18 :             const double time = StringUtils::toDouble(st2.next());
     756           18 :             result.add(time, StringUtils::toDouble(st2.next()));
     757           18 :         }
     758              :     }
     759           19 :     return result;
     760            0 : }
     761              : 
     762              : 
     763              : void
     764          193 : ODMatrix::sortByBeginTime() {
     765          193 :     std::sort(myContainer.begin(), myContainer.end(), cell_by_begin_comparator());
     766          193 : }
     767              : 
     768              : 
     769              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1