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

Generated by: LCOV version 2.0-1