SUMO - Simulation of Urban MObility

od2trips_main.cpp

Go to the documentation of this file.
00001 /****************************************************************************/
00010 // Main for OD2TRIPS
00011 /****************************************************************************/
00012 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/
00013 // Copyright (C) 2001-2012 DLR (http://www.dlr.de/) and contributors
00014 /****************************************************************************/
00015 //
00016 //   This file is part of SUMO.
00017 //   SUMO is free software: you can redistribute it and/or modify
00018 //   it under the terms of the GNU General Public License as published by
00019 //   the Free Software Foundation, either version 3 of the License, or
00020 //   (at your option) any later version.
00021 //
00022 /****************************************************************************/
00023 
00024 
00025 // ===========================================================================
00026 // included modules
00027 // ===========================================================================
00028 #ifdef _MSC_VER
00029 #include <windows_config.h>
00030 #else
00031 #include <config.h>
00032 #endif
00033 
00034 #ifdef HAVE_VERSION_H
00035 #include <version.h>
00036 #endif
00037 
00038 #include <iostream>
00039 #include <algorithm>
00040 #include <math.h>
00041 #include <cstdlib>
00042 #include <string>
00043 #include <xercesc/parsers/SAXParser.hpp>
00044 #include <xercesc/sax2/SAX2XMLReader.hpp>
00045 #include <utils/options/Option.h>
00046 #include <utils/options/OptionsCont.h>
00047 #include <utils/options/OptionsIO.h>
00048 #include <utils/common/MsgHandler.h>
00049 #include <utils/common/UtilExceptions.h>
00050 #include <utils/common/SystemFrame.h>
00051 #include <utils/common/RandHelper.h>
00052 #include <utils/common/ToString.h>
00053 #include <utils/xml/XMLSubSys.h>
00054 #include <utils/common/StringUtils.h>
00055 #include <od2trips/ODDistrictCont.h>
00056 #include <od2trips/ODDistrictHandler.h>
00057 #include <od2trips/ODMatrix.h>
00058 #include <utils/common/TplConvert.h>
00059 #include <utils/common/SUMOTime.h>
00060 #include <utils/common/StringTokenizer.h>
00061 #include <utils/common/FileHelpers.h>
00062 #include <utils/common/FileHelpers.h>
00063 #include <utils/common/SUMOVehicleParameter.h>
00064 #include <utils/importio/LineReader.h>
00065 #include <utils/iodevices/OutputDevice.h>
00066 #include <utils/common/SUMOTime.h>
00067 
00068 #ifdef CHECK_MEMORY_LEAKS
00069 #include <foreign/nvwa/debug_new.h>
00070 #endif // CHECK_MEMORY_LEAKS
00071 
00072 
00073 // ===========================================================================
00074 // functions
00075 // ===========================================================================
00076 void
00077 fillOptions() {
00078     OptionsCont& oc = OptionsCont::getOptions();
00079     oc.addCallExample("-c <CONFIGURATION>");
00080 
00081     // insert options sub-topics
00082     SystemFrame::addConfigurationOptions(oc); // fill this subtopic, too
00083     oc.addOptionSubTopic("Input");
00084     oc.addOptionSubTopic("Output");
00085     oc.addOptionSubTopic("Time");
00086     oc.addOptionSubTopic("Processing");
00087     oc.addOptionSubTopic("Defaults");
00088     SystemFrame::addReportOptions(oc); // fill this subtopic, too
00089 
00090 
00091     // register the file input options
00092     oc.doRegister("net-file", 'n', new Option_FileName());
00093     oc.addSynonyme("net-file", "net");
00094     oc.addDescription("net-file", "Input", "Loads network (districts) from FILE");
00095 
00096     oc.doRegister("od-matrix-files", 'd', new Option_FileName());
00097     oc.addSynonyme("od-matrix-files", "od-files");
00098     oc.addSynonyme("od-matrix-files", "od");
00099     oc.addDescription("od-matrix-files", "Input", "Loads O/D-files from FILE(s)");
00100 
00101 
00102     // register the file output options
00103     oc.doRegister("output-file", 'o', new Option_FileName());
00104     oc.addSynonyme("output-file", "output", true);
00105     oc.addDescription("output-file", "Output", "Writes trip definitions into FILE");
00106 
00107     oc.doRegister("ignore-vehicle-type", new Option_Bool(false));
00108     oc.addSynonyme("ignore-vehicle-type", "no-vtype", true);
00109     oc.addDescription("ignore-vehicle-type", "Output", "Does not save vtype information");
00110 
00111 
00112     // register the time settings
00113     oc.doRegister("begin", 'b', new Option_String("0", "TIME"));
00114     oc.addDescription("begin", "Time", "Defines the begin time; Previous trips will be discarded");
00115 
00116     oc.doRegister("end", 'e', new Option_String(SUMOTIME_MAXSTRING, "TIME"));
00117     oc.addDescription("end", "Time", "Defines the end time; Later trips will be discarded; Defaults to the maximum time that SUMO can represent");
00118 
00119 
00120     // register the data processing options
00121     oc.doRegister("scale", 's', new Option_Float(1));
00122     oc.addDescription("scale", "Processing", "Scales the loaded flows by FLOAT");
00123 
00124     oc.doRegister("spread.uniform", new Option_Bool(false));
00125     oc.addDescription("spread.uniform", "Processing", "Spreads trips uniformly over each time period");
00126 
00127     oc.doRegister("vtype", new Option_String(""));
00128     oc.addDescription("vtype", "Processing", "Defines the name of the vehicle type to use");
00129 
00130     oc.doRegister("prefix", new Option_String(""));
00131     oc.addDescription("prefix", "Processing", "Defines the prefix for vehicle names");
00132 
00133     oc.doRegister("timeline", new Option_String());
00134     oc.addDescription("timeline", "Processing", "Uses STR as a timeline definition");
00135 
00136     oc.doRegister("timeline.day-in-hours", new Option_Bool(false));
00137     oc.addDescription("timeline.day-in-hours", "Processing", "Uses STR as a 24h-timeline definition");
00138 
00139     oc.doRegister("dismiss-loading-errors", new Option_Bool(false)); // !!! describe, document
00140     oc.addDescription("dismiss-loading-errors", "Processing", "Continue on broken input");
00141 
00142 
00143     // register defaults options
00144     oc.doRegister("departlane", new Option_String("free"));
00145     oc.addDescription("departlane", "Defaults", "Assigns a default depart lane");
00146 
00147     oc.doRegister("departpos", new Option_String());
00148     oc.addDescription("departpos", "Defaults", "Assigns a default depart position");
00149 
00150     oc.doRegister("departspeed", new Option_String("max"));
00151     oc.addDescription("departspeed", "Defaults", "Assigns a default depart speed");
00152 
00153     oc.doRegister("arrivallane", new Option_String());
00154     oc.addDescription("arrivallane", "Defaults", "Assigns a default arrival lane");
00155 
00156     oc.doRegister("arrivalpos", new Option_String());
00157     oc.addDescription("arrivalpos", "Defaults", "Assigns a default arrival position");
00158 
00159     oc.doRegister("arrivalspeed", new Option_String());
00160     oc.addDescription("arrivalspeed", "Defaults", "Assigns a default arrival speed");
00161 
00162     // add rand options
00163     RandHelper::insertRandOptions();
00164 }
00165 
00166 
00167 Distribution_Points
00168 parseTimeLine(const std::vector<std::string> &def, bool timelineDayInHours) {
00169     bool interpolating = !timelineDayInHours;
00170     PositionVector points;
00171     SUMOReal prob = 0;
00172     if (timelineDayInHours) {
00173         if (def.size() != 24) {
00174             throw ProcessError("Assuming 24 entries for a day timeline, but got " + toString(def.size()) + ".");
00175         }
00176         for (int chour = 0; chour < 24; ++chour) {
00177             prob = TplConvert<char>::_2SUMOReal(def[chour].c_str());
00178             points.push_back(Position((SUMOReal)(chour * 3600), prob));
00179         }
00180         points.push_back(Position((SUMOReal)(24 * 3600), prob));
00181     } else {
00182         size_t i = 0;
00183         while (i < def.size()) {
00184             StringTokenizer st2(def[i++], ":");
00185             if (st2.size() != 2) {
00186                 throw ProcessError("Broken time line definition: missing a value in '" + def[i - 1] + "'.");
00187             }
00188             int time = TplConvert<char>::_2int(st2.next().c_str());
00189             prob = TplConvert<char>::_2SUMOReal(st2.next().c_str());
00190             points.push_back(Position((SUMOReal) time, prob));
00191         }
00192     }
00193     return Distribution_Points("N/A", points, interpolating);
00194 }
00195 
00196 
00197 bool
00198 checkOptions() {
00199     OptionsCont& oc = OptionsCont::getOptions();
00200     bool ok = true;
00201     if (!oc.isSet("net-file")) {
00202         WRITE_ERROR("No net input file (-n) specified.");
00203         ok = false;
00204     }
00205     if (!oc.isSet("od-matrix-files")) {
00206         WRITE_ERROR("No input specified.");
00207         ok = false;
00208     }
00209     if (!oc.isSet("output-file")) {
00210         WRITE_ERROR("No trip table output file (-o) specified.");
00211         ok = false;
00212     }
00213     //
00214     ok &= (!oc.isSet("departlane") || SUMOVehicleParameter::departlaneValidate(oc.getString("departlane")));
00215     ok &= (!oc.isSet("departpos") || SUMOVehicleParameter::departposValidate(oc.getString("departpos")));
00216     ok &= (!oc.isSet("departspeed") || SUMOVehicleParameter::departspeedValidate(oc.getString("departspeed")));
00217     ok &= (!oc.isSet("arrivallane") || SUMOVehicleParameter::arrivallaneValidate(oc.getString("arrivallane")));
00218     ok &= (!oc.isSet("arrivalpos") || SUMOVehicleParameter::arrivalposValidate(oc.getString("arrivalpos")));
00219     ok &= (!oc.isSet("arrivalspeed") || SUMOVehicleParameter::arrivalspeedValidate(oc.getString("arrivalspeed")));
00220     return ok;
00221 }
00222 
00223 
00224 void
00225 loadDistricts(ODDistrictCont& districts, OptionsCont& oc) {
00226     // check whether the user gave a net filename
00227     if (!oc.isSet("net-file")) {
00228         WRITE_ERROR("You must supply a network ('-n').");
00229         return;
00230     }
00231     // get the file name and set it
00232     std::string file = oc.getString("net-file");
00233     if (!FileHelpers::exists(file)) {
00234         throw ProcessError("Could not find network '" + file + "' to load.");
00235     }
00236     PROGRESS_BEGIN_MESSAGE("Loading districts from '" + file + "'");
00237     // build the xml-parser and handler
00238     ODDistrictHandler handler(districts, file);
00239     if (!XMLSubSys::runParser(handler, file)) {
00240         PROGRESS_FAILED_MESSAGE();
00241     } else {
00242         PROGRESS_DONE_MESSAGE();
00243     }
00244 }
00245 
00246 
00247 std::string
00248 getNextNonCommentLine(LineReader& lr) {
00249     std::string line;
00250     do {
00251         line = lr.readLine();
00252         if (line[0] != '*') {
00253             return StringUtils::prune(line);
00254         }
00255     } while (lr.good() && lr.hasMore());
00256     throw ProcessError();
00257 }
00258 
00259 
00260 SUMOTime
00261 parseSingleTime(const std::string& time) {
00262     if (time.find('.') == std::string::npos) {
00263         throw OutOfBoundsException();
00264     }
00265     std::string hours = time.substr(0, time.find('.'));
00266     std::string minutes = time.substr(time.find('.') + 1);
00267     return (SUMOTime) TplConvert<char>::_2int(hours.c_str()) * 3600 + TplConvert<char>::_2int(minutes.c_str()) * 60;
00268 }
00269 
00270 
00271 std::pair<SUMOTime, SUMOTime>
00272 readTime(LineReader& lr) {
00273     std::string line = getNextNonCommentLine(lr);
00274     try {
00275         StringTokenizer st(line, StringTokenizer::WHITECHARS);
00276         SUMOTime begin = parseSingleTime(st.next());
00277         SUMOTime end = parseSingleTime(st.next());
00278         if (begin >= end) {
00279             throw ProcessError("Begin time is larger than end time.");
00280         }
00281         return std::make_pair(begin, end);
00282     } catch (OutOfBoundsException&) {
00283         throw ProcessError("Broken period definition '" + line + "'.");
00284     } catch (NumberFormatException&) {
00285         throw ProcessError("Broken period definition '" + line + "'.");
00286     }
00287 }
00288 
00289 
00290 SUMOReal
00291 readFactor(LineReader& lr, SUMOReal scale) {
00292     std::string line = getNextNonCommentLine(lr);
00293     SUMOReal factor = -1;
00294     try {
00295         factor = TplConvert<char>::_2SUMOReal(line.c_str()) * scale;
00296     } catch (NumberFormatException&) {
00297         throw ProcessError("Broken factor: '" + line + "'.");
00298     }
00299     return factor;
00300 }
00301 
00302 
00303 
00304 void
00305 readV(LineReader& lr, ODMatrix& into, SUMOReal scale,
00306       std::string vehType, bool matrixHasVehType) {
00307     PROGRESS_BEGIN_MESSAGE("Reading matrix '" + lr.getFileName() + "' stored as VMR");
00308     // parse first defs
00309     std::string line;
00310     if (matrixHasVehType) {
00311         line = getNextNonCommentLine(lr);
00312         if (vehType == "") {
00313             vehType = StringUtils::prune(line);
00314         }
00315     }
00316 
00317     // parse time
00318     std::pair<SUMOTime, SUMOTime> times = readTime(lr);
00319     SUMOTime begin = times.first;
00320     SUMOTime end = times.second;
00321 
00322     // factor
00323     SUMOReal factor = readFactor(lr, scale);
00324 
00325     // districts
00326     line = getNextNonCommentLine(lr);
00327     int districtNo = TplConvert<char>::_2int(StringUtils::prune(line).c_str());
00328     // parse district names (normally ints)
00329     std::vector<std::string> names;
00330     do {
00331         line = getNextNonCommentLine(lr);
00332         StringTokenizer st2(line, StringTokenizer::WHITECHARS);
00333         while (st2.hasNext()) {
00334             names.push_back(st2.next());
00335         }
00336     } while ((int) names.size() != districtNo);
00337 
00338     // parse the cells
00339     for (std::vector<std::string>::iterator si = names.begin(); si != names.end(); ++si) {
00340         std::vector<std::string>::iterator di = names.begin();
00341         //
00342         do {
00343             line = getNextNonCommentLine(lr);
00344             if (line.length() == 0) {
00345                 continue;
00346             }
00347             try {
00348                 StringTokenizer st2(line, StringTokenizer::WHITECHARS);
00349                 while (st2.hasNext()) {
00350                     assert(di != names.end());
00351                     SUMOReal vehNumber = TplConvert<char>::_2SUMOReal(st2.next().c_str()) * factor;
00352                     if (vehNumber != 0) {
00353                         into.add(vehNumber, begin, end, *si, *di, vehType);
00354                     }
00355                     if (di == names.end()) {
00356                         throw ProcessError("More entries than districts found.");
00357                     }
00358                     ++di;
00359                 }
00360             } catch (NumberFormatException&) {
00361                 throw ProcessError("Not numeric vehicle number in line '" + line + "'.");
00362             }
00363             if (!lr.hasMore()) {
00364                 break;
00365             }
00366         } while (di != names.end());
00367     }
00368     PROGRESS_DONE_MESSAGE();
00369 }
00370 
00371 
00372 void
00373 readO(LineReader& lr, ODMatrix& into, SUMOReal scale,
00374       std::string vehType, bool matrixHasVehType) {
00375     PROGRESS_BEGIN_MESSAGE("Reading matrix '" + lr.getFileName() + "' stored as OR");
00376     // parse first defs
00377     std::string line;
00378     if (matrixHasVehType) {
00379         line = getNextNonCommentLine(lr);
00380         int type = TplConvert<char>::_2int(StringUtils::prune(line).c_str());
00381         if (vehType == "") {
00382             vehType = toString(type);
00383         }
00384     }
00385 
00386     // parse time
00387     std::pair<SUMOTime, SUMOTime> times = readTime(lr);
00388     SUMOTime begin = times.first;
00389     SUMOTime end = times.second;
00390 
00391     // factor
00392     SUMOReal factor = readFactor(lr, scale);
00393 
00394     // parse the cells
00395     while (lr.hasMore()) {
00396         line = getNextNonCommentLine(lr);
00397         if (line.length() == 0) {
00398             continue;
00399         }
00400         StringTokenizer st2(line, StringTokenizer::WHITECHARS);
00401         if (st2.size() == 0) {
00402             continue;
00403         }
00404         try {
00405             std::string sourceD = st2.next();
00406             std::string destD = st2.next();
00407             SUMOReal vehNumber = TplConvert<char>::_2SUMOReal(st2.next().c_str()) * factor;
00408             if (vehNumber != 0) {
00409                 into.add(vehNumber, begin, end, sourceD, destD, vehType);
00410             }
00411         } catch (OutOfBoundsException&) {
00412             throw ProcessError("Missing at least one information in line '" + line + "'.");
00413         } catch (NumberFormatException&) {
00414             throw ProcessError("Not numeric vehicle number in line '" + line + "'.");
00415         }
00416     }
00417     PROGRESS_DONE_MESSAGE();
00418 }
00419 
00420 
00421 void
00422 loadMatrix(OptionsCont& oc, ODMatrix& into) {
00423     std::vector<std::string> files = oc.getStringVector("od-files");
00424     //  check
00425     if (files.size() == 0) {
00426         throw ProcessError("No files to parse are given.");
00427     }
00428     //  parse
00429     for (std::vector<std::string>::iterator i = files.begin(); i != files.end(); ++i) {
00430         LineReader lr(*i);
00431         if (!lr.good()) {
00432             throw ProcessError("Could not open '" + (*i) + "'.");
00433         }
00434         std::string type = lr.readLine();
00435         // get the type only
00436         if (type.find(';') != std::string::npos) {
00437             type = type.substr(0, type.find(';'));
00438         }
00439         // parse type-dependant
00440         if (type.length() > 1 && type[1] == 'V') {
00441             // process ptv's 'V'-matrices
00442             if (type.find('N') != std::string::npos) {
00443                 throw ProcessError("'" + *i + "' does not contain the needed information about the time described.");
00444             }
00445             readV(lr, into, oc.getFloat("scale"), oc.getString("vtype"), type.find('M') != std::string::npos);
00446         } else if (type.length() > 1 && type[1] == 'O') {
00447             // process ptv's 'O'-matrices
00448             if (type.find('N') != std::string::npos) {
00449                 throw ProcessError("'" + *i + "' does not contain the needed information about the time described.");
00450             }
00451             readO(lr, into, oc.getFloat("scale"), oc.getString("vtype"), type.find('M') != std::string::npos);
00452         } else {
00453             throw ProcessError("'" + *i + "' uses an unknown matrix type '" + type + "'.");
00454         }
00455     }
00456 }
00457 
00458 
00459 /* -------------------------------------------------------------------------
00460  * main
00461  * ----------------------------------------------------------------------- */
00462 int
00463 main(int argc, char** argv) {
00464     OptionsCont& oc = OptionsCont::getOptions();
00465     // give some application descriptions
00466     oc.setApplicationDescription("Importer of O/D-matrices for the road traffic simulation SUMO.");
00467     oc.setApplicationName("od2trips", "SUMO od2trips Version " + (std::string)VERSION_STRING);
00468     int ret = 0;
00469     try {
00470         // initialise subsystems
00471         XMLSubSys::init(false);
00472         fillOptions();
00473         OptionsIO::getOptions(true, argc, argv);
00474         if (oc.processMetaOptions(argc < 2)) {
00475             SystemFrame::close();
00476             return 0;
00477         }
00478         MsgHandler::initOutputOptions();
00479         if (!checkOptions()) {
00480             throw ProcessError();
00481         }
00482         RandHelper::initRandGlobal();
00483         // load the districts
00484         ODDistrictCont districts;
00485         loadDistricts(districts, oc);
00486         if (districts.size() == 0) {
00487             throw ProcessError("No districts loaded...");
00488         }
00489         // load the matrix
00490         ODMatrix matrix(districts);
00491         loadMatrix(oc, matrix);
00492         if (matrix.getNoLoaded() == 0) {
00493             throw ProcessError("No vehicles loaded...");
00494         }
00495         if (MsgHandler::getErrorInstance()->wasInformed() && !oc.getBool("dismiss-loading-errors")) {
00496             throw ProcessError("Loading failed...");
00497         }
00498         WRITE_MESSAGE(toString(matrix.getNoLoaded()) + " vehicles loaded.");
00499         // apply a curve if wished
00500         if (oc.isSet("timeline")) {
00501             matrix.applyCurve(parseTimeLine(oc.getStringVector("timeline"), oc.getBool("timeline.day-in-hours")));
00502         }
00503         // write
00504         if (!OutputDevice::createDeviceByOption("output-file", "trips")) {
00505             throw ProcessError("No output name is given.");
00506         }
00507         OutputDevice& dev = OutputDevice::getDeviceByOption("output-file");
00508         matrix.write(SUMOTime(string2time(oc.getString("begin")) / 1000.), SUMOTime(string2time(oc.getString("end")) / 1000.),
00509                      dev, oc.getBool("spread.uniform"), oc.getBool("ignore-vehicle-type"), oc.getString("prefix"));
00510         WRITE_MESSAGE(toString(matrix.getNoDiscarded()) + " vehicles discarded.");
00511         WRITE_MESSAGE(toString(matrix.getNoWritten()) + " vehicles written.");
00512     } catch (ProcessError& e) {
00513         if (std::string(e.what()) != std::string("Process Error") && std::string(e.what()) != std::string("")) {
00514             WRITE_ERROR(e.what());
00515         }
00516         MsgHandler::getErrorInstance()->inform("Quitting (on error).", false);
00517         ret = 1;
00518 #ifndef _DEBUG
00519     } catch (...) {
00520         MsgHandler::getErrorInstance()->inform("Quitting (on unknown error).", false);
00521         ret = 1;
00522 #endif
00523     }
00524     SystemFrame::close();
00525     OutputDevice::closeAll();
00526     if (ret == 0) {
00527         std::cout << "Success." << std::endl;
00528     }
00529     return ret;
00530 }
00531 
00532 
00533 
00534 /****************************************************************************/
00535 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Defines