00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
00063 #ifdef CHECK_MEMORY_LEAKS
00064 #include <foreign/nvwa/debug_new.h>
00065 #endif // CHECK_MEMORY_LEAKS
00066
00067
00068
00069
00070
00071 void
00072 fillOptions() {
00073 OptionsCont &oc = OptionsCont::getOptions();
00074 oc.addCallExample("-c <CONFIGURATION>");
00075
00076
00077 SystemFrame::addConfigurationOptions(oc);
00078 oc.addOptionSubTopic("Input");
00079 oc.addOptionSubTopic("Output");
00080 oc.addOptionSubTopic("Time");
00081 oc.addOptionSubTopic("Processing");
00082 oc.addOptionSubTopic("Defaults");
00083 SystemFrame::addReportOptions(oc);
00084
00085
00086
00087 oc.doRegister("net-file", 'n', new Option_FileName());
00088 oc.addSynonyme("net-file", "net");
00089 oc.addDescription("net-file", "Input", "Loads network (districts) from FILE");
00090
00091 oc.doRegister("od-files", 'd', new Option_FileName());
00092 oc.addSynonyme("od-files", "od");
00093 oc.addDescription("od-files", "Input", "Loads O/D-files from FILE(s)");
00094
00095
00096
00097 oc.doRegister("output-file", 'o', new Option_FileName());
00098 oc.addSynonyme("output-file", "output");
00099 oc.addDescription("output-file", "Output", "Writes trip definitions into FILE");
00100
00101 oc.doRegister("no-vtype", new Option_Bool(false));
00102 oc.addDescription("no-vtype", "Output", "Does not save vtype information");
00103
00104 oc.doRegister("with-taz", new Option_Bool(false));
00105 oc.addDescription("with-taz", "Output", "Include origin and destination zones (districts)");
00106
00107
00108
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("86400", "TIME"));
00113 oc.addDescription("end", "Time", "Defines the end time; Later trips will be discarded");
00114
00115
00116
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));
00136 oc.addDescription("dismiss-loading-errors", "Processing", "Continue on broken input");
00137
00138
00139
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
00159 RandHelper::insertRandOptions();
00160 }
00161
00162
00163 Distribution_Points
00164 parseTimeLine(const std::vector<std::string> &def, bool timelineDayInHours) {
00165 bool interpolating = !timelineDayInHours;
00166 Position2DVector 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(Position2D((SUMOReal)(chour*3600), prob));
00175 }
00176 points.push_back(Position2D((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(Position2D((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 MsgHandler::getErrorInstance()->inform("No net input file (-n) specified.");
00199 ok = false;
00200 }
00201 if (!oc.isSet("od-files")) {
00202 MsgHandler::getErrorInstance()->inform("No input specified.");
00203 ok = false;
00204 }
00205 if (!oc.isSet("output")) {
00206 MsgHandler::getErrorInstance()->inform("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
00223 if (!oc.isSet("net-file")) {
00224 MsgHandler::getErrorInstance()->inform("You must supply a network ('-n').");
00225 return;
00226 }
00227
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 MsgHandler::getMessageInstance()->beginProcessMsg("Loading districts from '" + file + "'...");
00233
00234 ODDistrictHandler handler(districts, file);
00235 if (!XMLSubSys::runParser(handler, file)) {
00236 MsgHandler::getMessageInstance()->endProcessMsg("failed.");
00237 } else {
00238 MsgHandler::getMessageInstance()->endProcessMsg("done.");
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 MsgHandler::getMessageInstance()->beginProcessMsg("Reading matrix '" + lr.getFileName() + "' stored as VMR...");
00304
00305 std::string line;
00306 if (matrixHasVehType) {
00307 line = getNextNonCommentLine(lr);
00308 if (vehType=="") {
00309 vehType = StringUtils::prune(line);
00310 }
00311 }
00312
00313
00314 std::pair<SUMOTime, SUMOTime> times = readTime(lr);
00315 SUMOTime begin = times.first;
00316 SUMOTime end = times.second;
00317
00318
00319 SUMOReal factor = readFactor(lr, scale);
00320
00321
00322 line = getNextNonCommentLine(lr);
00323 int districtNo = TplConvert<char>::_2int(StringUtils::prune(line).c_str());
00324
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
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 MsgHandler::getMessageInstance()->endProcessMsg("done.");
00365 }
00366
00367
00368 void
00369 readO(LineReader &lr, ODMatrix &into, SUMOReal scale,
00370 std::string vehType, bool matrixHasVehType) {
00371 MsgHandler::getMessageInstance()->beginProcessMsg("Reading matrix '" + lr.getFileName() + "' stored as OR...");
00372
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
00383 std::pair<SUMOTime, SUMOTime> times = readTime(lr);
00384 SUMOTime begin = times.first;
00385 SUMOTime end = times.second;
00386
00387
00388 SUMOReal factor = readFactor(lr, scale);
00389
00390
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 MsgHandler::getMessageInstance()->endProcessMsg("done.");
00414 }
00415
00416
00417 void
00418 loadMatrix(OptionsCont &oc, ODMatrix &into) {
00419 std::vector<std::string> files = oc.getStringVector("od-files");
00420
00421 if (files.size()==0) {
00422 throw ProcessError("No files to parse are given.");
00423 }
00424
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
00432 if (type.find(';')!=std::string::npos) {
00433 type = type.substr(0, type.find(';'));
00434 }
00435
00436 if (type.length()>1 && type[1]=='V') {
00437
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
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
00457
00458 int
00459 main(int argc, char **argv) {
00460 OptionsCont &oc = OptionsCont::getOptions();
00461
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
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()) throw ProcessError();
00476 RandHelper::initRandGlobal();
00477
00478 ODDistrictCont districts;
00479 loadDistricts(districts, oc);
00480 if (districts.size()==0) {
00481 throw ProcessError("No districts loaded...");
00482 }
00483
00484 ODMatrix matrix(districts);
00485 loadMatrix(oc, matrix);
00486 if (matrix.getNoLoaded()==0) {
00487 throw ProcessError("No vehicles loaded...");
00488 }
00489 if (MsgHandler::getErrorInstance()->wasInformed()&&!oc.getBool("dismiss-loading-errors")) {
00490 throw ProcessError("Loading failed...");
00491 }
00492 MsgHandler::getMessageInstance()->inform(toString(matrix.getNoLoaded()) + " vehicles loaded.");
00493
00494 if (oc.isSet("timeline")) {
00495 matrix.applyCurve(parseTimeLine(oc.getStringVector("timeline"), oc.getBool("timeline.day-in-hours")));
00496 }
00497
00498 if (!OutputDevice::createDeviceByOption("output", "tripdefs")) {
00499 throw ProcessError("No output name is given.");
00500 }
00501 OutputDevice& dev = OutputDevice::getDeviceByOption("output");
00502 matrix.write(string2time(oc.getString("begin"))/1000., string2time(oc.getString("end"))/1000.,
00503 dev, oc.getBool("spread.uniform"), oc.getBool("no-vtype"), oc.getString("prefix"));
00504 MsgHandler::getMessageInstance()->inform(toString(matrix.getNoDiscarded()) + " vehicles discarded.");
00505 MsgHandler::getMessageInstance()->inform(toString(matrix.getNoWritten()) + " vehicles written.");
00506 } catch (ProcessError &e) {
00507 if (std::string(e.what())!=std::string("Process Error") && std::string(e.what())!=std::string("")) {
00508 MsgHandler::getErrorInstance()->inform(e.what());
00509 }
00510 MsgHandler::getErrorInstance()->inform("Quitting (on error).", false);
00511 ret = 1;
00512 #ifndef _DEBUG
00513 } catch (...) {
00514 MsgHandler::getErrorInstance()->inform("Quitting (on unknown error).", false);
00515 ret = 1;
00516 #endif
00517 }
00518 SystemFrame::close();
00519 OutputDevice::closeAll();
00520 if (ret==0) {
00521 std::cout << "Success." << std::endl;
00522 }
00523 return ret;
00524 }
00525
00526
00527
00528
00529