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