LCOV - code coverage report
Current view: top level - src/od - ODMatrix.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 94.2 % 428 403
Test Date: 2026-04-16 16:39:47 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          246 : ODMatrix::ODMatrix(const ODDistrictCont& dc, double scale) :
      53          246 :     myDistricts(dc),
      54          246 :     myNumLoaded(0),
      55          246 :     myNumWritten(0),
      56          246 :     myNumDiscarded(0),
      57          246 :     myBegin(-1),
      58          246 :     myEnd(-1),
      59          246 :     myScale(scale)
      60          246 : {}
      61              : 
      62              : 
      63          246 : ODMatrix::~ODMatrix() {
      64         9212 :     for (ODCell* const cell : myContainer) {
      65         8966 :         delete cell;
      66              :     }
      67              :     myContainer.clear();
      68          492 : }
      69              : 
      70              : 
      71              : bool
      72          819 : 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          819 :     if (vehicleNumber == 0) {
      77              :         return false;
      78              :     }
      79          819 :     myNumLoaded += vehicleNumber;
      80          828 :     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          814 :     } 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          805 :     } 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         1579 :     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         1555 :     } 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          772 :     ODCell* cell = new ODCell();
     107          772 :     cell->begin = beginEnd.first;
     108          772 :     cell->end = beginEnd.second;
     109          772 :     cell->origin = origin;
     110          772 :     cell->destination = destination;
     111          772 :     cell->vehicleType = vehicleType;
     112          772 :     cell->vehicleNumber = vehicleNumber * (noScaling ? 1 : myScale);
     113          772 :     cell->originIsEdge = originIsEdge;
     114          772 :     cell->destinationIsEdge = destinationIsEdge;
     115          772 :     myContainer.push_back(cell);
     116          772 :     if (myBegin == -1 || cell->begin < myBegin) {
     117          207 :         myBegin = cell->begin;
     118              :     }
     119          772 :     if (cell->end > myEnd) {
     120          207 :         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        16885 : ODMatrix::writeDefaultAttrs(OutputDevice& dev, const bool noVtype,
     205              :                             const ODCell* const cell) {
     206        16885 :     const OptionsCont& oc = OptionsCont::getOptions();
     207        16885 :     if (!noVtype && cell->vehicleType != "") {
     208         1942 :         dev.writeAttr(SUMO_ATTR_TYPE, cell->vehicleType);
     209              :     }
     210        16885 :     dev.writeAttr(SUMO_ATTR_FROM_TAZ, cell->origin).writeAttr(SUMO_ATTR_TO_TAZ, cell->destination);
     211        50655 :     if (oc.isSet("departlane") && oc.getString("departlane") != "default") {
     212        33770 :         dev.writeAttr(SUMO_ATTR_DEPARTLANE, oc.getString("departlane"));
     213              :     }
     214        33770 :     if (oc.isSet("departpos")) {
     215            2 :         dev.writeAttr(SUMO_ATTR_DEPARTPOS, oc.getString("departpos"));
     216              :     }
     217        50655 :     if (oc.isSet("departspeed") && oc.getString("departspeed") != "default") {
     218        33770 :         dev.writeAttr(SUMO_ATTR_DEPARTSPEED, oc.getString("departspeed"));
     219              :     }
     220        33770 :     if (oc.isSet("arrivallane")) {
     221            2 :         dev.writeAttr(SUMO_ATTR_ARRIVALLANE, oc.getString("arrivallane"));
     222              :     }
     223        33770 :     if (oc.isSet("arrivalpos")) {
     224            2 :         dev.writeAttr(SUMO_ATTR_ARRIVALPOS, oc.getString("arrivalpos"));
     225              :     }
     226        33770 :     if (oc.isSet("arrivalspeed")) {
     227            2 :         dev.writeAttr(SUMO_ATTR_ARRIVALSPEED, oc.getString("arrivalspeed"));
     228              :     }
     229        16885 : }
     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           32 : ODMatrix::writeFlows(const SUMOTime begin, const SUMOTime end,
     344              :                      OutputDevice& dev, bool noVtype,
     345              :                      const std::string& prefix,
     346              :                      bool asProbability, bool pedestrians, bool persontrips,
     347              :                      const std::string& modes) {
     348           32 :     if (myContainer.size() == 0) {
     349              :         return;
     350              :     }
     351              :     int flowName = 0;
     352           32 :     sortByBeginTime();
     353              :     // recheck begin time
     354          207 :     for (std::vector<ODCell*>::const_iterator i = myContainer.begin(); i != myContainer.end(); ++i) {
     355          175 :         const ODCell* const c = *i;
     356          175 :         if (c->end > begin && c->begin < end) {
     357          175 :             const double probability = asProbability ? float(c->vehicleNumber) / STEPS2TIME(c->end - c->begin) : 1;
     358          175 :             if (probability <= 0) {
     359           72 :                 continue;
     360              :             }
     361              :             //Person flows
     362          103 :             if (pedestrians) {
     363            4 :                 dev.openTag(SUMO_TAG_PERSONFLOW).writeAttr(SUMO_ATTR_ID, prefix + toString(flowName++));
     364            4 :                 dev.writeAttr(SUMO_ATTR_BEGIN, time2string(c->begin)).writeAttr(SUMO_ATTR_END, time2string(c->end));
     365            4 :                 if (!asProbability) {
     366            4 :                     dev.writeAttr(SUMO_ATTR_NUMBER, int(c->vehicleNumber));
     367              :                 } else {
     368            0 :                     if (probability > 1) {
     369            0 :                         WRITE_WARNINGF(TL("Flow density of % vehicles per second, cannot be represented with a simple probability. Falling back to even spacing."), toString(probability));
     370            0 :                         dev.writeAttr(SUMO_ATTR_NUMBER, int(c->vehicleNumber));
     371              :                     } else {
     372            0 :                         dev.setPrecision(6);
     373            0 :                         dev.writeAttr(SUMO_ATTR_PROB, probability);
     374            0 :                         dev.setPrecision();
     375              :                     }
     376              :                 }
     377            4 :                 dev.openTag(SUMO_TAG_WALK);
     378            4 :                 dev.writeAttr(SUMO_ATTR_FROM_TAZ, c->origin).writeAttr(SUMO_ATTR_TO_TAZ, c->destination);
     379            4 :                 dev.writeAttr(SUMO_ATTR_ARRIVALPOS, "random");
     380            4 :                 dev.closeTag();
     381            8 :                 dev.closeTag();
     382           99 :             } else if (persontrips) {
     383           14 :                 dev.openTag(SUMO_TAG_PERSONFLOW).writeAttr(SUMO_ATTR_ID, prefix + toString(flowName++));
     384           14 :                 dev.writeAttr(SUMO_ATTR_BEGIN, time2string(c->begin)).writeAttr(SUMO_ATTR_END, time2string(c->end));
     385           14 :                 if (!asProbability) {
     386           12 :                     dev.writeAttr(SUMO_ATTR_NUMBER, int(c->vehicleNumber));
     387              :                 } else {
     388            2 :                     if (probability > 1) {
     389            2 :                         WRITE_WARNINGF(TL("Flow density of % vehicles per second, cannot be represented with a simple probability. Falling back to even spacing."), toString(probability));
     390            1 :                         dev.writeAttr(SUMO_ATTR_NUMBER, int(c->vehicleNumber));
     391              :                     } else {
     392            1 :                         dev.setPrecision(6);
     393            1 :                         dev.writeAttr(SUMO_ATTR_PROB, probability);
     394            1 :                         dev.setPrecision();
     395              :                     }
     396              :                 }
     397           14 :                 dev.openTag(SUMO_TAG_PERSONTRIP);
     398           14 :                 dev.writeAttr(SUMO_ATTR_FROM_TAZ, c->origin).writeAttr(SUMO_ATTR_TO_TAZ, c->destination);
     399           14 :                 dev.writeAttr(SUMO_ATTR_ARRIVALPOS, "random");
     400           14 :                 if (modes != "") {
     401            0 :                     dev.writeAttr(SUMO_ATTR_MODES, modes);
     402              :                 }
     403           14 :                 dev.closeTag();
     404           28 :                 dev.closeTag();
     405              :             } else {
     406              :                 // Normal flow output
     407           85 :                 dev.openTag(SUMO_TAG_FLOW).writeAttr(SUMO_ATTR_ID, prefix + toString(flowName++));
     408           85 :                 dev.writeAttr(SUMO_ATTR_BEGIN, time2string(c->begin));
     409           85 :                 dev.writeAttr(SUMO_ATTR_END, time2string(c->end));
     410              : 
     411           85 :                 if (!asProbability) {
     412           10 :                     dev.writeAttr(SUMO_ATTR_NUMBER, int(c->vehicleNumber));
     413              :                 } else {
     414           75 :                     if (probability > 1) {
     415            2 :                         WRITE_WARNINGF(TL("Flow density of % vehicles per second, cannot be represented with a simple probability. Falling back to even spacing."), toString(probability));
     416            1 :                         dev.writeAttr(SUMO_ATTR_NUMBER, int(c->vehicleNumber));
     417              :                     } else {
     418           74 :                         dev.setPrecision(6);
     419           74 :                         dev.writeAttr(SUMO_ATTR_PROB, probability);
     420           74 :                         dev.setPrecision();
     421              :                     }
     422              :                 }
     423           85 :                 writeDefaultAttrs(dev, noVtype, *i);
     424          170 :                 dev.closeTag();
     425              :             }
     426              :         }
     427              :     }
     428              : }
     429              : 
     430              : 
     431              : std::string
     432          927 : ODMatrix::getNextNonCommentLine(LineReader& lr) {
     433         2185 :     while (lr.good() && lr.hasMore()) {
     434         2184 :         const std::string line = lr.readLine();
     435         2184 :         if (line[0] != '*') {
     436         1852 :             return StringUtils::prune(line);
     437              :         }
     438              :     }
     439            2 :     throw ProcessError(TLF("End of file while reading %.", lr.getFileName()));
     440              : }
     441              : 
     442              : 
     443              : SUMOTime
     444          348 : ODMatrix::parseSingleTime(const std::string& time) {
     445          348 :     if (time.find('.') == std::string::npos) {
     446           16 :         throw NumberFormatException("no separator");
     447              :     }
     448          340 :     const std::string hours = time.substr(0, time.find('.'));
     449          340 :     const std::string minutes = time.substr(time.find('.') + 1);
     450          680 :     return TIME2STEPS(StringUtils::toInt(hours) * 3600 + StringUtils::toInt(minutes) * 60);
     451              : }
     452              : 
     453              : 
     454              : std::pair<SUMOTime, SUMOTime>
     455          178 : ODMatrix::readTime(LineReader& lr) {
     456          178 :     std::string line = getNextNonCommentLine(lr);
     457              :     try {
     458          356 :         StringTokenizer st(line, StringTokenizer::WHITECHARS);
     459          178 :         const SUMOTime begin = parseSingleTime(st.next());
     460          174 :         const SUMOTime end = parseSingleTime(st.next());
     461          166 :         if (begin >= end) {
     462           16 :             throw ProcessError("Matrix begin time " + time2string(begin) + " is larger than end time " + time2string(end) + ".");
     463              :         }
     464          162 :         return std::make_pair(begin, end);
     465          194 :     } catch (OutOfBoundsException&) {
     466           12 :         throw ProcessError(TLF("Broken period definition '%'.", line));
     467           12 :     } catch (NumberFormatException& e) {
     468           24 :         throw ProcessError("Broken period definition '" + line + "' (" + e.what() + ").");
     469            8 :     }
     470              : }
     471              : 
     472              : 
     473              : double
     474          162 : ODMatrix::readFactor(LineReader& lr, double scale) {
     475          162 :     std::string line = getNextNonCommentLine(lr);
     476              :     double factor = -1;
     477              :     try {
     478          162 :         factor = StringUtils::toDouble(line) * scale;
     479            6 :     } catch (NumberFormatException&) {
     480           18 :         throw ProcessError(TLF("Broken factor: '%'.", line));
     481            6 :     }
     482          156 :     return factor;
     483              : }
     484              : 
     485              : void
     486           66 : ODMatrix::readV(LineReader& lr, double scale,
     487              :                 std::string vehType, bool matrixHasVehType) {
     488          198 :     PROGRESS_BEGIN_MESSAGE("Reading matrix '" + lr.getFileName() + "' stored as VMR");
     489              :     // parse first defs
     490              :     std::string line;
     491           66 :     if (matrixHasVehType) {
     492           37 :         line = getNextNonCommentLine(lr);
     493           37 :         if (vehType == "") {
     494           74 :             vehType = StringUtils::prune(line);
     495              :         }
     496              :     }
     497              : 
     498           66 :     const std::pair<SUMOTime, SUMOTime> beginEnd = readTime(lr);
     499           58 :     const double factor = readFactor(lr, scale);
     500              : 
     501              :     // districts
     502           56 :     line = getNextNonCommentLine(lr);
     503           78 :     const int numDistricts = StringUtils::toInt(StringUtils::prune(line));
     504              :     // parse district names (normally ints)
     505              :     std::vector<std::string> names;
     506          134 :     while ((int)names.size() != numDistricts && lr.hasMore()) {
     507           78 :         line = getNextNonCommentLine(lr);
     508          156 :         StringTokenizer st2(line, StringTokenizer::WHITECHARS);
     509          392 :         while (st2.hasNext()) {
     510          628 :             names.push_back(st2.next());
     511              :         }
     512           78 :     }
     513           56 :     if (!lr.hasMore()) {
     514            6 :         throw ProcessError(TLF("Missing line with % district names.", toString(numDistricts)));
     515              :     }
     516              : 
     517              :     // parse the cells
     518          204 :     for (std::vector<std::string>::iterator si = names.begin(); si != names.end(); ++si) {
     519              :         std::vector<std::string>::iterator di = names.begin();
     520              :         do {
     521              :             try {
     522          369 :                 line = getNextNonCommentLine(lr);
     523            1 :             } catch (ProcessError&) {
     524            3 :                 throw ProcessError(TLF("Missing line for district %.", (*si)));
     525            1 :             }
     526          184 :             if (line.length() == 0) {
     527            1 :                 continue;
     528              :             }
     529              :             try {
     530          366 :                 StringTokenizer st2(line, StringTokenizer::WHITECHARS);
     531          951 :                 while (st2.hasNext()) {
     532              :                     assert(di != names.end());
     533          776 :                     double vehNumber = StringUtils::toDouble(st2.next()) * factor;
     534          768 :                     if (vehNumber != 0) {
     535          556 :                         add(vehNumber, beginEnd, *si, *di, vehType);
     536              :                     }
     537          768 :                     if (di == names.end()) {
     538            0 :                         throw ProcessError(TL("More entries than districts found."));
     539              :                     }
     540              :                     ++di;
     541              :                 }
     542          191 :             } catch (NumberFormatException&) {
     543           24 :                 throw ProcessError(TLF("Not numeric vehicle number in line '%'.", line));
     544            8 :             }
     545          175 :             if (!lr.hasMore()) {
     546              :                 break;
     547              :             }
     548          137 :         } while (di != names.end());
     549              :     }
     550           44 :     PROGRESS_DONE_MESSAGE();
     551          100 : }
     552              : 
     553              : 
     554              : void
     555          112 : ODMatrix::readO(LineReader& lr, double scale,
     556              :                 std::string vehType, bool matrixHasVehType) {
     557          336 :     PROGRESS_BEGIN_MESSAGE("Reading matrix '" + lr.getFileName() + "' stored as OR");
     558              :     // parse first defs
     559              :     std::string line;
     560          112 :     if (matrixHasVehType) {
     561           11 :         line = getNextNonCommentLine(lr);
     562           11 :         int type = StringUtils::toInt(StringUtils::prune(line));
     563           11 :         if (vehType == "") {
     564           22 :             vehType = toString(type);
     565              :         }
     566              :     }
     567              : 
     568          112 :     const std::pair<SUMOTime, SUMOTime> beginEnd = readTime(lr);
     569          104 :     const double factor = readFactor(lr, scale);
     570              : 
     571              :     // parse the cells
     572          318 :     while (lr.hasMore()) {
     573          440 :         line = getNextNonCommentLine(lr);
     574          220 :         if (line.length() == 0) {
     575           25 :             continue;
     576              :         }
     577          404 :         StringTokenizer st2(line, StringTokenizer::WHITECHARS);
     578          195 :         if (st2.size() == 0) {
     579              :             continue;
     580              :         }
     581              :         try {
     582          195 :             std::string sourceD = st2.next();
     583          195 :             std::string destD = st2.next();
     584          197 :             double vehNumber = StringUtils::toDouble(st2.next()) * factor;
     585          193 :             if (vehNumber != 0) {
     586          193 :                 add(vehNumber, beginEnd, sourceD, destD, vehType);
     587              :             }
     588            2 :         } catch (OutOfBoundsException&) {
     589            0 :             throw ProcessError(TLF("Missing at least one information in line '%'.", line));
     590            2 :         } catch (NumberFormatException&) {
     591            6 :             throw ProcessError(TLF("Not numeric vehicle number in line '%'.", line));
     592            2 :         }
     593          195 :     }
     594           98 :     PROGRESS_DONE_MESSAGE();
     595           98 : }
     596              : 
     597              : 
     598              : 
     599              : double
     600          466 : ODMatrix::getNumLoaded() const {
     601          466 :     return myNumLoaded;
     602              : }
     603              : 
     604              : 
     605              : double
     606          107 : ODMatrix::getNumWritten() const {
     607          107 :     return myNumWritten;
     608              : }
     609              : 
     610              : 
     611              : double
     612          268 : ODMatrix::getNumDiscarded() const {
     613          268 :     return myNumDiscarded;
     614              : }
     615              : 
     616              : 
     617              : void
     618          362 : ODMatrix::applyCurve(const Distribution_Points& ps, ODCell* cell, std::vector<ODCell*>& newCells) {
     619              :     const std::vector<double>& times = ps.getVals();
     620         8918 :     for (int i = 0; i < (int)times.size() - 1; ++i) {
     621         8556 :         ODCell* ncell = new ODCell();
     622         8556 :         ncell->begin = TIME2STEPS(times[i]);
     623         8556 :         ncell->end = TIME2STEPS(times[i + 1]);
     624         8556 :         ncell->origin = cell->origin;
     625         8556 :         ncell->destination = cell->destination;
     626         8556 :         ncell->vehicleType = cell->vehicleType;
     627         8556 :         ncell->vehicleNumber = cell->vehicleNumber * ps.getProbs()[i] / ps.getOverallProb();
     628         8556 :         newCells.push_back(ncell);
     629              :     }
     630          362 : }
     631              : 
     632              : 
     633              : void
     634           19 : ODMatrix::applyCurve(const Distribution_Points& ps) {
     635           19 :     std::vector<ODCell*> oldCells = myContainer;
     636              :     myContainer.clear();
     637          381 :     for (std::vector<ODCell*>::iterator i = oldCells.begin(); i != oldCells.end(); ++i) {
     638              :         std::vector<ODCell*> newCells;
     639          362 :         applyCurve(ps, *i, newCells);
     640              :         copy(newCells.begin(), newCells.end(), back_inserter(myContainer));
     641          362 :         delete *i;
     642          362 :     }
     643           19 : }
     644              : 
     645              : 
     646              : void
     647          246 : ODMatrix::loadMatrix(OptionsCont& oc) {
     648          492 :     std::vector<std::string> files = oc.getStringVector("od-matrix-files");
     649          388 :     for (std::vector<std::string>::iterator i = files.begin(); i != files.end(); ++i) {
     650          180 :         LineReader lr(*i);
     651          180 :         if (!lr.good()) {
     652            6 :             throw ProcessError(TLF("Could not open '%'.", (*i)));
     653              :         }
     654          178 :         std::string type = lr.readLine();
     655              :         // get the type only
     656          178 :         if (type.find(';') != std::string::npos) {
     657          250 :             type = type.substr(0, type.find(';'));
     658              :         }
     659              :         // parse type-dependant
     660          178 :         if (type.length() > 1 && type[1] == 'V') {
     661              :             // process ptv's 'V'-matrices
     662           66 :             if (type.find('N') != std::string::npos) {
     663            0 :                 throw ProcessError(TLF("'%' does not contain the needed information about the time described.", *i));
     664              :             }
     665          110 :             readV(lr, 1, oc.getString("vtype"), type.find('M') != std::string::npos);
     666          112 :         } else if (type.length() > 1 && type[1] == 'O') {
     667              :             // process ptv's 'O'-matrices
     668          112 :             if (type.find('N') != std::string::npos) {
     669            0 :                 throw ProcessError(TLF("'%' does not contain the needed information about the time described.", *i));
     670              :             }
     671          246 :             readO(lr, 1, oc.getString("vtype"), type.find('M') != std::string::npos);
     672              :         } else {
     673            0 :             throw ProcessError("'" + *i + "' uses an unknown matrix type '" + type + "'.");
     674              :         }
     675          180 :     }
     676          416 :     std::vector<std::string> amitranFiles = oc.getStringVector("od-amitran-files");
     677          235 :     for (std::vector<std::string>::iterator i = amitranFiles.begin(); i != amitranFiles.end(); ++i) {
     678           54 :         if (!FileHelpers::isReadable(*i)) {
     679            0 :             throw ProcessError(TLF("Could not access matrix file '%' to load.", *i));
     680              :         }
     681           81 :         PROGRESS_BEGIN_MESSAGE("Loading matrix in Amitran format from '" + *i + "'");
     682           27 :         ODAmitranHandler handler(*this, *i);
     683           27 :         if (!XMLSubSys::runParser(handler, *i)) {
     684            4 :             PROGRESS_FAILED_MESSAGE();
     685              :         } else {
     686           23 :             PROGRESS_DONE_MESSAGE();
     687              :         }
     688           27 :     }
     689          208 :     myVType = oc.getString("vtype");
     690          423 :     for (std::string file : oc.getStringVector("tazrelation-files")) {
     691           14 :         if (!FileHelpers::isReadable(file)) {
     692            0 :             throw ProcessError(TLF("Could not access matrix file '%' to load.", file));
     693              :         }
     694           21 :         PROGRESS_BEGIN_MESSAGE("Loading matrix in tazRelation format from '" + file + "'");
     695              : 
     696              :         std::vector<SAXWeightsHandler::ToRetrieveDefinition*> retrieverDefs;
     697            7 :         retrieverDefs.push_back(new SAXWeightsHandler::ToRetrieveDefinition(oc.getString("tazrelation-attribute"), true, *this));
     698            7 :         SAXWeightsHandler handler(retrieverDefs, "");
     699            7 :         if (!XMLSubSys::runParser(handler, file)) {
     700            0 :             PROGRESS_FAILED_MESSAGE();
     701              :         } else {
     702            7 :             PROGRESS_DONE_MESSAGE();
     703              :         }
     704            7 :     }
     705          246 : }
     706              : 
     707              : void
     708            7 : ODMatrix::addTazRelWeight(const std::string intervalID, const std::string& from, const std::string& to,
     709              :                           double val, double beg, double end) {
     710            8 :     add(val, std::make_pair(TIME2STEPS(beg), TIME2STEPS(end)), from, to, myVType == "" ? intervalID : myVType);
     711            7 : }
     712              : 
     713              : 
     714              : void
     715           86 : ODMatrix::loadRoutes(OptionsCont& oc, SUMOSAXHandler& handler) {
     716          172 :     std::vector<std::string> routeFiles = oc.getStringVector("route-files");
     717          119 :     for (std::vector<std::string>::iterator i = routeFiles.begin(); i != routeFiles.end(); ++i) {
     718           66 :         if (!FileHelpers::isReadable(*i)) {
     719            0 :             throw ProcessError(TLF("Could not access route file '%' to load.", *i));
     720              :         }
     721           99 :         PROGRESS_BEGIN_MESSAGE("Loading routes and trips from '" + *i + "'");
     722           33 :         if (!XMLSubSys::runParser(handler, *i)) {
     723            1 :             PROGRESS_FAILED_MESSAGE();
     724              :         } else {
     725           32 :             PROGRESS_DONE_MESSAGE();
     726              :         }
     727              :     }
     728           86 : }
     729              : 
     730              : 
     731              : Distribution_Points
     732           19 : ODMatrix::parseTimeLine(const std::vector<std::string>& def, bool timelineDayInHours) {
     733           19 :     Distribution_Points result("N/A");
     734           19 :     if (timelineDayInHours) {
     735           13 :         if (def.size() != 24) {
     736            0 :             throw ProcessError(TLF("Assuming 24 entries for a day timeline, but got %.", toString(def.size())));
     737              :         }
     738          325 :         for (int chour = 0; chour < 24; ++chour) {
     739          312 :             result.add(chour * 3600., StringUtils::toDouble(def[chour]));
     740              :         }
     741           13 :         result.add(24 * 3600., 0.); // dummy value to finish the last interval
     742              :     } else {
     743           24 :         for (int i = 0; i < (int)def.size(); i++) {
     744           54 :             StringTokenizer st2(def[i], ":");
     745           18 :             if (st2.size() != 2) {
     746            0 :                 throw ProcessError(TLF("Broken time line definition: missing a value in '%'.", def[i]));
     747              :             }
     748           18 :             const double time = StringUtils::toDouble(st2.next());
     749           18 :             result.add(time, StringUtils::toDouble(st2.next()));
     750           18 :         }
     751              :     }
     752           19 :     return result;
     753            0 : }
     754              : 
     755              : 
     756              : void
     757          192 : ODMatrix::sortByBeginTime() {
     758          192 :     std::sort(myContainer.begin(), myContainer.end(), cell_by_begin_comparator());
     759          192 : }
     760              : 
     761              : 
     762              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1