diff --git a/src/cppgtfs b/src/cppgtfs index 520be35..7496330 160000 --- a/src/cppgtfs +++ b/src/cppgtfs @@ -1 +1 @@ -Subproject commit 520be35426083e96e6adc0d1a7915c9640b1f4e3 +Subproject commit 7496330a36bdfa7a3cdacff26d785a0607e63328 diff --git a/src/pfaedle/PfaedleMain.cpp b/src/pfaedle/PfaedleMain.cpp index ca7ac3b..0db163e 100644 --- a/src/pfaedle/PfaedleMain.cpp +++ b/src/pfaedle/PfaedleMain.cpp @@ -86,6 +86,9 @@ enum class RetCode { std::string getFileNameMotStr(const MOTs& mots); std::vector getCfgPaths(const Config& cfg); +// _____________________________________________________________________________ +void gtfsWarnCb(std::string msg) { LOG(WARN) << msg; } + // _____________________________________________________________________________ int main(int argc, char** argv) { // disable output buffering for standard output @@ -136,7 +139,8 @@ int main(int argc, char** argv) { LOG(INFO) << "Reading GTFS feed " << cfg.feedPaths[0] << " ..."; try { ad::cppgtfs::Parser p(cfg.feedPaths[0], false, - cfg.parseAdditionalGTFSFields); + cfg.parseAdditionalGTFSFields, + cfg.verbosity ? gtfsWarnCb : 0); p.parse(>fs[0]); } catch (const ad::cppgtfs::ParserException& ex) { LOG(ERROR) << "Could not parse input GTFS feed, reason was:"; @@ -193,7 +197,7 @@ int main(int argc, char** argv) { for (size_t i = 0; i < cfg.feedPaths.size(); i++) { ShapeBuilder::getGtfsBox(>fs[i], cmdCfgMots, cfg.shapeTripId, true, - &box, maxSpeed, 0); + &box, maxSpeed, 0, cfg.verbosity); } OsmBuilder osmBuilder; std::vector opts; @@ -215,7 +219,7 @@ int main(int argc, char** argv) { BBoxIdx box(BOX_PADDING); for (size_t i = 0; i < cfg.feedPaths.size(); i++) { ShapeBuilder::getGtfsBox(>fs[i], cmdCfgMots, cfg.shapeTripId, true, - &box, maxSpeed, 0); + &box, maxSpeed, 0, cfg.verbosity); } OsmBuilder osmBuilder; std::vector opts; @@ -270,9 +274,9 @@ int main(int argc, char** argv) { pfaedle::osm::OsmBuilder osmBuilder; pfaedle::osm::BBoxIdx box(BOX_PADDING); - ShapeBuilder::getGtfsBox(>fs[0], usedMots, cfg.shapeTripId, - cfg.dropShapes, &box, - motCfg.osmBuildOpts.maxSpeed, &hopDists); + ShapeBuilder::getGtfsBox( + >fs[0], usedMots, cfg.shapeTripId, cfg.dropShapes, &box, + motCfg.osmBuildOpts.maxSpeed, &hopDists, cfg.verbosity); T_START(osmBuild); diff --git a/src/pfaedle/config/ConfigReader.cpp b/src/pfaedle/config/ConfigReader.cpp index d3acdd7..9e62a96 100644 --- a/src/pfaedle/config/ConfigReader.cpp +++ b/src/pfaedle/config/ConfigReader.cpp @@ -111,6 +111,8 @@ void ConfigReader::help(const char* bin) { << "Disable hop cache \n" << std::setw(35) << " --stats" << "write stats to stats.json\n" + << std::setw(35) << " -W [ --warn ]" + << "enable verbose warning messages\n" << std::setw(35) << " -P" << "additional parameter string (in cfg file format)\n"; } @@ -144,11 +146,12 @@ void ConfigReader::read(Config* cfg, int argc, char** argv) { {"stats", no_argument, 0, 14}, {"no-hop-cache", no_argument, 0, 15}, {"gaussian-noise", required_argument, 0, 16}, + {"warn", no_argument, 0, 'W'}, {"keep-additional-gtfs-fields", no_argument, 0, 'F'}, {0, 0, 0, 0}}; int c; - while ((c = getopt_long(argc, argv, ":o:hvi:c:x:Dm:g:X:T:d:pP:F", ops, 0)) != + while ((c = getopt_long(argc, argv, ":o:hvi:c:x:Dm:g:X:T:d:pP:FW", ops, 0)) != -1) { switch (c) { case 1: @@ -220,6 +223,9 @@ void ConfigReader::read(Config* cfg, int argc, char** argv) { case 16: cfg->gaussianNoise = atof(optarg); break; + case 'W': + cfg->verbosity = 1; + break; case 'F': cfg->parseAdditionalGTFSFields = true; break; diff --git a/src/pfaedle/config/PfaedleConfig.h b/src/pfaedle/config/PfaedleConfig.h index 7ad045c..211ada3 100644 --- a/src/pfaedle/config/PfaedleConfig.h +++ b/src/pfaedle/config/PfaedleConfig.h @@ -39,7 +39,8 @@ struct Config { writeStats(false), parseAdditionalGTFSFields(false), gridSize(2000 / util::geo::M_PER_DEG), - gaussianNoise(0) {} + gaussianNoise(0), + verbosity(0) {} std::string dbgOutputPath; std::string solveMethod; std::string shapeTripId; @@ -67,6 +68,7 @@ struct Config { bool parseAdditionalGTFSFields; double gridSize; double gaussianNoise; + uint8_t verbosity; std::string toString() { std::stringstream ss; @@ -88,6 +90,7 @@ struct Config { << "no-a-star: " << noAStar << "\n" << "no-trie: " << noTrie << "\n" << "no-hop-cache: " << noHopCache << "\n" + << "verbosity: " << verbosity << "\n" << "parse-additional-gtfs-fields: " << parseAdditionalGTFSFields << "\n" << "write-stats: " << writeStats << "\n" << "feed-paths: "; diff --git a/src/pfaedle/router/ShapeBuilder.cpp b/src/pfaedle/router/ShapeBuilder.cpp index 5b72b2d..a17de80 100644 --- a/src/pfaedle/router/ShapeBuilder.cpp +++ b/src/pfaedle/router/ShapeBuilder.cpp @@ -73,7 +73,7 @@ ShapeBuilder::ShapeBuilder( _router(router) { pfaedle::osm::BBoxIdx box(BOX_PADDING); ShapeBuilder::getGtfsBox(feed, mots, cfg.shapeTripId, cfg.dropShapes, &box, - _motCfg.osmBuildOpts.maxSpeed, 0); + _motCfg.osmBuildOpts.maxSpeed, 0, cfg.verbosity); _eGrid = EdgeGrid(cfg.gridSize, cfg.gridSize, box.getFullBox(), false); _nGrid = NodeGrid(cfg.gridSize, cfg.gridSize, box.getFullBox(), false); @@ -270,6 +270,11 @@ EdgeCandGroup ShapeBuilder::getEdgCands(const Stop* s) const { {}}); } + if (ret.size() == 1 && _cfg.verbosity) { + LOG(WARN) << "No snapping candidate found for stop '" << s->getName() + << "' (" << s->getId() << ")"; + } + return ret; } @@ -321,7 +326,7 @@ std::pair, Stats> ShapeBuilder::shapeL(Trip* trip) { LOG(INFO) << "Matched 1 trip in " << std::fixed << std::setprecision(2) << stats.solveTime << " ms."; // print to line - return {getGeom(hops, getRAttrs(trip), &colors), stats}; + return {getGeom(hops, getRAttrs(trip), &colors, trip, 1), stats}; } catch (const std::runtime_error& e) { LOG(ERROR) << e.what(); return {std::vector(), stats}; @@ -558,15 +563,16 @@ void ShapeBuilder::setShape(Trip* t, const ad::cppgtfs::gtfs::Shape& s, // _____________________________________________________________________________ ad::cppgtfs::gtfs::Shape ShapeBuilder::getGtfsShape( - const EdgeListHops& hops, Trip* t, const RoutingAttrs& rAttrs, - std::vector* hopDists, uint32_t* bestColor) { + const EdgeListHops& hops, Trip* t, size_t numOthers, + const RoutingAttrs& rAttrs, std::vector* hopDists, + uint32_t* bestColor) { ad::cppgtfs::gtfs::Shape ret(getFreeShapeId(t)); assert(hops.size() == t->getStopTimes().size() - 1); std::map colors; - const std::vector& gl = getGeom(hops, rAttrs, &colors); + const std::vector& gl = getGeom(hops, rAttrs, &colors, t, numOthers); const std::vector& measures = getMeasure(gl); size_t seq = 0; @@ -651,7 +657,8 @@ const RoutingAttrs& ShapeBuilder::getRAttrs(const Trip* trip) const { void ShapeBuilder::getGtfsBox(const Feed* feed, const MOTs& mots, const std::string& tid, bool dropShapes, osm::BBoxIdx* box, double maxSpeed, - std::vector* hopDists) { + std::vector* hopDists, + uint8_t verbosity) { for (const auto& t : feed->getTrips()) { if (!tid.empty() && t.getId() != tid) continue; if (tid.empty() && !t.getShape().empty() && !dropShapes) continue; @@ -695,11 +702,21 @@ void ShapeBuilder::getGtfsBox(const Feed* feed, const MOTs& mots, if (reqToTime > (BUFFER + toTime) * 3 * MAX_ROUTE_COST_DOUBLING_STEPS && reqFromTime > (BUFFER + fromTime) * 3 * MAX_ROUTE_COST_DOUBLING_STEPS) { - LOG(DEBUG) << "Skipping station " << st.getStop()->getId() << " (" - << st.getStop()->getName() << ") @ " - << st.getStop()->getLat() << ", " << st.getStop()->getLng() - << " for bounding box as the vehicle cannot realistically " - "reach and leave it in the scheduled time"; + if (verbosity) { + LOG(WARN) + << "Skipping station '" << st.getStop()->getName() << "' (" + << st.getStop()->getId() << ") @ " << st.getStop()->getLat() + << ", " << st.getStop()->getLng() + << " for bounding box as the vehicle cannot realistically " + "reach and leave it in the scheduled time"; + } else { + LOG(DEBUG) + << "Skipping station '" << st.getStop()->getName() << "' (" + << st.getStop()->getId() << ") @ " << st.getStop()->getLat() + << ", " << st.getStop()->getLng() + << " for bounding box as the vehicle cannot realistically " + "reach and leave it in the scheduled time"; + } continue; } @@ -954,9 +971,10 @@ void ShapeBuilder::buildNetGraph(TrGraphEdgs* edgs, } // _____________________________________________________________________________ -std::vector ShapeBuilder::getGeom( - const EdgeListHops& hops, const RoutingAttrs& rAttrs, - std::map* colors) const { +std::vector ShapeBuilder::getGeom(const EdgeListHops& hops, + const RoutingAttrs& rAttrs, + std::map* colors, + Trip* t, size_t numOthers) const { std::vector ret; for (size_t i = hops.size(); i > 0; i--) { @@ -964,6 +982,23 @@ std::vector ShapeBuilder::getGeom( if (!hop.start || !hop.end) { // no hop was found, use the fallback geometry + if (_cfg.verbosity) { + const auto stopFr = t->getStopTimes()[hops.size() - i].getStop(); + const auto stopTo = t->getStopTimes()[hops.size() - i + 1].getStop(); + + LOG(WARN) << "No viable hop found between stops '" << stopFr->getName() + << "' (" << stopFr->getId() << ") and '" << stopTo->getName() + << "' (" << stopTo->getId() << ") for trip " << t->getId() + << " of type '" + << ad::cppgtfs::gtfs::flat::Route::getTypeString( + t->getRoute()->getType()) + << "'" + << (numOthers > 1 ? " (and " + std::to_string(numOthers) + + " similar trips)" + : "") + << ", falling back to straight line"; + } + if (hop.start) { if (hop.progrStart > 0) { auto l = getLine(hop.start); @@ -1159,8 +1194,9 @@ void ShapeBuilder::shapeWorker( uint32_t color; - const ad::cppgtfs::gtfs::Shape& shp = getGtfsShape( - hops.at(leaf.first), leaf.second[0], rAttrs, &distances, &color); + const ad::cppgtfs::gtfs::Shape& shp = + getGtfsShape(hops.at(leaf.first), leaf.second[0], + leaf.second.size(), rAttrs, &distances, &color); if (_cfg.buildTransitGraph) { writeTransitGraph(hops.at(leaf.first), gtfsGraph, leaf.second); diff --git a/src/pfaedle/router/ShapeBuilder.h b/src/pfaedle/router/ShapeBuilder.h index 662ca59..c0309e2 100644 --- a/src/pfaedle/router/ShapeBuilder.h +++ b/src/pfaedle/router/ShapeBuilder.h @@ -12,6 +12,7 @@ #include #include #include + #include "ad/cppgtfs/gtfs/Feed.h" #include "pfaedle/Def.h" #include "pfaedle/config/MotConfig.h" @@ -73,7 +74,7 @@ class ShapeBuilder { static void getGtfsBox(const pfaedle::gtfs::Feed* feed, const MOTs& mots, const std::string& tid, bool dropShapes, osm::BBoxIdx* box, double maxSpeed, - std::vector* hopDists); + std::vector* hopDists, uint8_t verbosity); private: pfaedle::gtfs::Feed* _feed; @@ -103,6 +104,7 @@ class ShapeBuilder { std::string getFreeShapeId(pfaedle::gtfs::Trip* t); ad::cppgtfs::gtfs::Shape getGtfsShape(const EdgeListHops& shp, pfaedle::gtfs::Trip* t, + size_t numOthers, const RoutingAttrs& rAttrs, std::vector* hopDists, uint32_t* bestColor); @@ -126,7 +128,8 @@ class ShapeBuilder { void buildIndex(); std::vector getGeom(const EdgeListHops& shp, const RoutingAttrs& rAttrs, - std::map* colors) const; + std::map* colors, Trip* t, + size_t numOthers) const; double timePen(int candTime, int schedTime) const; LINE getLine(const EdgeListHop& hop, const RoutingAttrs&,