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>", "run with configuration file");
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     oc.doRegister("no-step-log", new Option_Bool(false));
00143     oc.addDescription("no-step-log", "Processing", "Disable console output of current time step");
00144 
00145 
00146     // register defaults options
00147     oc.doRegister("departlane", new Option_String("free"));
00148     oc.addDescription("departlane", "Defaults", "Assigns a default depart lane");
00149 
00150     oc.doRegister("departpos", new Option_String());
00151     oc.addDescription("departpos", "Defaults", "Assigns a default depart position");
00152 
00153     oc.doRegister("departspeed", new Option_String("max"));
00154     oc.addDescription("departspeed", "Defaults", "Assigns a default depart speed");
00155 
00156     oc.doRegister("arrivallane", new Option_String());
00157     oc.addDescription("arrivallane", "Defaults", "Assigns a default arrival lane");
00158 
00159     oc.doRegister("arrivalpos", new Option_String());
00160     oc.addDescription("arrivalpos", "Defaults", "Assigns a default arrival position");
00161 
00162     oc.doRegister("arrivalspeed", new Option_String());
00163     oc.addDescription("arrivalspeed", "Defaults", "Assigns a default arrival speed");
00164 
00165     // add rand options
00166     RandHelper::insertRandOptions();
00167 }
00168 
00169 
00170 Distribution_Points
00171 parseTimeLine(const std::vector<std::string> &def, bool timelineDayInHours) {
00172     bool interpolating = !timelineDayInHours;
00173     PositionVector points;
00174     SUMOReal prob = 0;
00175     if (timelineDayInHours) {
00176         if (def.size() != 24) {
00177             throw ProcessError("Assuming 24 entries for a day timeline, but got " + toString(def.size()) + ".");
00178         }
00179         for (int chour = 0; chour < 24; ++chour) {
00180             prob = TplConvert<char>::_2SUMOReal(def[chour].c_str());
00181             points.push_back(Position((SUMOReal)(chour * 3600), prob));
00182         }
00183         points.push_back(Position((SUMOReal)(24 * 3600), prob));
00184     } else {
00185         size_t i = 0;
00186         while (i < def.size()) {
00187             StringTokenizer st2(def[i++], ":");
00188             if (st2.size() != 2) {
00189                 throw ProcessError("Broken time line definition: missing a value in '" + def[i - 1] + "'.");
00190             }
00191             int time = TplConvert<char>::_2int(st2.next().c_str());
00192             prob = TplConvert<char>::_2SUMOReal(st2.next().c_str());
00193             points.push_back(Position((SUMOReal) time, prob));
00194         }
00195     }
00196     return Distribution_Points("N/A", points, interpolating);
00197 }
00198 
00199 
00200 bool
00201 checkOptions() {
00202     OptionsCont& oc = OptionsCont::getOptions();
00203     bool ok = true;
00204     if (!oc.isSet("net-file")) {
00205         WRITE_ERROR("No net input file (-n) specified.");
00206         ok = false;
00207     }
00208     if (!oc.isSet("od-matrix-files")) {
00209         WRITE_ERROR("No input specified.");
00210         ok = false;
00211     }
00212     if (!oc.isSet("output-file")) {
00213         WRITE_ERROR("No trip table output file (-o) specified.");
00214         ok = false;
00215     }
00216     //
00217     ok &= (!oc.isSet("departlane") || SUMOVehicleParameter::departlaneValidate(oc.getString("departlane")));
00218     ok &= (!oc.isSet("departpos") || SUMOVehicleParameter::departposValidate(oc.getString("departpos")));
00219     ok &= (!oc.isSet("departspeed") || SUMOVehicleParameter::departspeedValidate(oc.getString("departspeed")));
00220     ok &= (!oc.isSet("arrivallane") || SUMOVehicleParameter::arrivallaneValidate(oc.getString("arrivallane")));
00221     ok &= (!oc.isSet("arrivalpos") || SUMOVehicleParameter::arrivalposValidate(oc.getString("arrivalpos")));
00222     ok &= (!oc.isSet("arrivalspeed") || SUMOVehicleParameter::arrivalspeedValidate(oc.getString("arrivalspeed")));
00223     return ok;
00224 }
00225 
00226 
00227 void
00228 loadDistricts(ODDistrictCont& districts, OptionsCont& oc) {
00229     // check whether the user gave a net filename
00230     if (!oc.isSet("net-file")) {
00231         WRITE_ERROR("You must supply a network ('-n').");
00232         return;
00233     }
00234     // get the file name and set it
00235     std::string file = oc.getString("net-file");
00236     if (!FileHelpers::exists(file)) {
00237         throw ProcessError("Could not find network '" + file + "' to load.");
00238     }
00239     PROGRESS_BEGIN_MESSAGE("Loading districts from '" + file + "'");
00240     // build the xml-parser and handler
00241     ODDistrictHandler handler(districts, file);
00242     if (!XMLSubSys::runParser(handler, file)) {
00243         PROGRESS_FAILED_MESSAGE();
00244     } else {
00245         PROGRESS_DONE_MESSAGE();
00246     }
00247 }
00248 
00249 
00250 std::string
00251 getNextNonCommentLine(LineReader& lr) {
00252     std::string line;
00253     do {
00254         line = lr.readLine();
00255         if (line[0] != '*') {
00256             return StringUtils::prune(line);
00257         }
00258     } while (lr.good() && lr.hasMore());
00259     throw ProcessError();
00260 }
00261 
00262 
00263 SUMOTime
00264 parseSingleTime(const std::string& time) {
00265     if (time.find('.') == std::string::npos) {
00266         throw OutOfBoundsException();
00267     }
00268     std::string hours = time.substr(0, time.find('.'));
00269     std::string minutes = time.substr(time.find('.') + 1);
00270     return (SUMOTime) TplConvert<char>::_2int(hours.c_str()) * 3600 + TplConvert<char>::_2int(minutes.c_str()) * 60;
00271 }
00272 
00273 
00274 std::pair<SUMOTime, SUMOTime>
00275 readTime(LineReader& lr) {
00276     std::string line = getNextNonCommentLine(lr);
00277     try {
00278         StringTokenizer st(line, StringTokenizer::WHITECHARS);
00279         SUMOTime begin = parseSingleTime(st.next());
00280         SUMOTime end = parseSingleTime(st.next());
00281         if (begin >= end) {
00282             throw ProcessError("Begin time is larger than end time.");
00283         }
00284         return std::make_pair(begin, end);
00285     } catch (OutOfBoundsException&) {
00286         throw ProcessError("Broken period definition '" + line + "'.");
00287     } catch (NumberFormatException&) {
00288         throw ProcessError("Broken period definition '" + line + "'.");
00289     }
00290 }
00291 
00292 
00293 SUMOReal
00294 readFactor(LineReader& lr, SUMOReal scale) {
00295     std::string line = getNextNonCommentLine(lr);
00296     SUMOReal factor = -1;
00297     try {
00298         factor = TplConvert<char>::_2SUMOReal(line.c_str()) * scale;
00299     } catch (NumberFormatException&) {
00300         throw ProcessError("Broken factor: '" + line + "'.");
00301     }
00302     return factor;
00303 }
00304 
00305 
00306 
00307 void
00308 readV(LineReader& lr, ODMatrix& into, SUMOReal scale,
00309       std::string vehType, bool matrixHasVehType) {
00310     PROGRESS_BEGIN_MESSAGE("Reading matrix '" + lr.getFileName() + "' stored as VMR");
00311     // parse first defs
00312     std::string line;
00313     if (matrixHasVehType) {
00314         line = getNextNonCommentLine(lr);
00315         if (vehType == "") {
00316             vehType = StringUtils::prune(line);
00317         }
00318     }
00319 
00320     // parse time
00321     std::pair<SUMOTime, SUMOTime> times = readTime(lr);
00322     SUMOTime begin = times.first;
00323     SUMOTime end = times.second;
00324 
00325     // factor
00326     SUMOReal factor = readFactor(lr, scale);
00327 
00328     // districts
00329     line = getNextNonCommentLine(lr);
00330     int districtNo = TplConvert<char>::_2int(StringUtils::prune(line).c_str());
00331     // parse district names (normally ints)
00332     std::vector<std::string> names;
00333     do {
00334         line = getNextNonCommentLine(lr);
00335         StringTokenizer st2(line, StringTokenizer::WHITECHARS);
00336         while (st2.hasNext()) {
00337             names.push_back(st2.next());
00338         }
00339     } while ((int) names.size() != districtNo);
00340 
00341     // parse the cells
00342     for (std::vector<std::string>::iterator si = names.begin(); si != names.end(); ++si) {
00343         std::vector<std::string>::iterator di = names.begin();
00344         //
00345         do {
00346             line = getNextNonCommentLine(lr);
00347             if (line.length() == 0) {
00348                 continue;
00349             }
00350             try {
00351                 StringTokenizer st2(line, StringTokenizer::WHITECHARS);
00352                 while (st2.hasNext()) {
00353                     assert(di != names.end());
00354                     SUMOReal vehNumber = TplConvert<char>::_2SUMOReal(st2.next().c_str()) * factor;
00355                     if (vehNumber != 0) {
00356                         into.add(vehNumber, begin, end, *si, *di, vehType);
00357                     }
00358                     if (di == names.end()) {
00359                         throw ProcessError("More entries than districts found.");
00360                     }
00361                     ++di;
00362                 }
00363             } catch (NumberFormatException&) {
00364                 throw ProcessError("Not numeric vehicle number in line '" + line + "'.");
00365             }
00366             if (!lr.hasMore()) {
00367                 break;
00368             }
00369         } while (di != names.end());
00370     }
00371     PROGRESS_DONE_MESSAGE();
00372 }
00373 
00374 
00375 void
00376 readO(LineReader& lr, ODMatrix& into, SUMOReal scale,
00377       std::string vehType, bool matrixHasVehType) {
00378     PROGRESS_BEGIN_MESSAGE("Reading matrix '" + lr.getFileName() + "' stored as OR");
00379     // parse first defs
00380     std::string line;
00381     if (matrixHasVehType) {
00382         line = getNextNonCommentLine(lr);
00383         int type = TplConvert<char>::_2int(StringUtils::prune(line).c_str());
00384         if (vehType == "") {
00385             vehType = toString(type);
00386         }
00387     }
00388 
00389     // parse time
00390     std::pair<SUMOTime, SUMOTime> times = readTime(lr);
00391     SUMOTime begin = times.first;
00392     SUMOTime end = times.second;
00393 
00394     // factor
00395     SUMOReal factor = readFactor(lr, scale);
00396 
00397     // parse the cells
00398     while (lr.hasMore()) {
00399         line = getNextNonCommentLine(lr);
00400         if (line.length() == 0) {
00401             continue;
00402         }
00403         StringTokenizer st2(line, StringTokenizer::WHITECHARS);
00404         if (st2.size() == 0) {
00405             continue;
00406         }
00407         try {
00408             std::string sourceD = st2.next();
00409             std::string destD = st2.next();
00410             SUMOReal vehNumber = TplConvert<char>::_2SUMOReal(st2.next().c_str()) * factor;
00411             if (vehNumber != 0) {
00412                 into.add(vehNumber, begin, end, sourceD, destD, vehType);
00413             }
00414         } catch (OutOfBoundsException&) {
00415             throw ProcessError("Missing at least one information in line '" + line + "'.");
00416         } catch (NumberFormatException&) {
00417             throw ProcessError("Not numeric vehicle number in line '" + line + "'.");
00418         }
00419     }
00420     PROGRESS_DONE_MESSAGE();
00421 }
00422 
00423 
00424 void
00425 loadMatrix(OptionsCont& oc, ODMatrix& into) {
00426     std::vector<std::string> files = oc.getStringVector("od-files");
00427     //  check
00428     if (files.size() == 0) {
00429         throw ProcessError("No files to parse are given.");
00430     }
00431     //  parse
00432     for (std::vector<std::string>::iterator i = files.begin(); i != files.end(); ++i) {
00433         LineReader lr(*i);
00434         if (!lr.good()) {
00435             throw ProcessError("Could not open '" + (*i) + "'.");
00436         }
00437         std::string type = lr.readLine();
00438         // get the type only
00439         if (type.find(';') != std::string::npos) {
00440             type = type.substr(0, type.find(';'));
00441         }
00442         // parse type-dependant
00443         if (type.length() > 1 && type[1] == 'V') {
00444             // process ptv's 'V'-matrices
00445             if (type.find('N') != std::string::npos) {
00446                 throw ProcessError("'" + *i + "' does not contain the needed information about the time described.");
00447             }
00448             readV(lr, into, oc.getFloat("scale"), oc.getString("vtype"), type.find('M') != std::string::npos);
00449         } else if (type.length() > 1 && type[1] == 'O') {
00450             // process ptv's 'O'-matrices
00451             if (type.find('N') != std::string::npos) {
00452                 throw ProcessError("'" + *i + "' does not contain the needed information about the time described.");
00453             }
00454             readO(lr, into, oc.getFloat("scale"), oc.getString("vtype"), type.find('M') != std::string::npos);
00455         } else {
00456             throw ProcessError("'" + *i + "' uses an unknown matrix type '" + type + "'.");
00457         }
00458     }
00459 }
00460 
00461 
00462 /* -------------------------------------------------------------------------
00463  * main
00464  * ----------------------------------------------------------------------- */
00465 int
00466 main(int argc, char** argv) {
00467     OptionsCont& oc = OptionsCont::getOptions();
00468     // give some application descriptions
00469     oc.setApplicationDescription("Importer of O/D-matrices for the road traffic simulation SUMO.");
00470     oc.setApplicationName("od2trips", "SUMO od2trips Version " + (std::string)VERSION_STRING);
00471     int ret = 0;
00472     try {
00473         // initialise subsystems
00474         XMLSubSys::init(false);
00475         fillOptions();
00476         OptionsIO::getOptions(true, argc, argv);
00477         if (oc.processMetaOptions(argc < 2)) {
00478             OutputDevice::closeAll();
00479             SystemFrame::close();
00480             return 0;
00481         }
00482         MsgHandler::initOutputOptions();
00483         if (!checkOptions()) {
00484             throw ProcessError();
00485         }
00486         RandHelper::initRandGlobal();
00487         // load the districts
00488         ODDistrictCont districts;
00489         loadDistricts(districts, oc);
00490         if (districts.size() == 0) {
00491             throw ProcessError("No districts loaded...");
00492         }
00493         // load the matrix
00494         ODMatrix matrix(districts);
00495         loadMatrix(oc, matrix);
00496         if (matrix.getNoLoaded() == 0) {
00497             throw ProcessError("No vehicles loaded...");
00498         }
00499         if (MsgHandler::getErrorInstance()->wasInformed() && !oc.getBool("dismiss-loading-errors")) {
00500             throw ProcessError("Loading failed...");
00501         }
00502         WRITE_MESSAGE(toString(matrix.getNoLoaded()) + " vehicles loaded.");
00503         // apply a curve if wished
00504         if (oc.isSet("timeline")) {
00505             matrix.applyCurve(parseTimeLine(oc.getStringVector("timeline"), oc.getBool("timeline.day-in-hours")));
00506         }
00507         // write
00508         if (!OutputDevice::createDeviceByOption("output-file", "trips")) {
00509             throw ProcessError("No output name is given.");
00510         }
00511         OutputDevice& dev = OutputDevice::getDeviceByOption("output-file");
00512         matrix.write(SUMOTime(string2time(oc.getString("begin")) / 1000.), SUMOTime(string2time(oc.getString("end")) / 1000.),
00513                      dev, oc.getBool("spread.uniform"), oc.getBool("ignore-vehicle-type"), oc.getString("prefix"), !oc.getBool("no-step-log"));
00514         WRITE_MESSAGE(toString(matrix.getNoDiscarded()) + " vehicles discarded.");
00515         WRITE_MESSAGE(toString(matrix.getNoWritten()) + " vehicles written.");
00516     } catch (ProcessError& e) {
00517         if (std::string(e.what()) != std::string("Process Error") && std::string(e.what()) != std::string("")) {
00518             WRITE_ERROR(e.what());
00519         }
00520         MsgHandler::getErrorInstance()->inform("Quitting (on error).", false);
00521         ret = 1;
00522 #ifndef _DEBUG
00523     } catch (...) {
00524         MsgHandler::getErrorInstance()->inform("Quitting (on unknown error).", false);
00525         ret = 1;
00526 #endif
00527     }
00528     SystemFrame::close();
00529     OutputDevice::closeAll();
00530     if (ret == 0) {
00531         std::cout << "Success." << std::endl;
00532     }
00533     return ret;
00534 }
00535 
00536 
00537 
00538 /****************************************************************************/
00539 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Defines