SUMO - Simulation of Urban MObility
|
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