/** \brief Setups scripting environment (lua-scripting) Also initializes speed profile. */ bool Prepare::SetupScriptingEnvironment(lua_State *lua_state, EdgeBasedGraphFactory::SpeedProfileProperties &speed_profile) { // open utility libraries string library; luaL_openlibs(lua_state); // adjust lua load path luaAddScriptFolderToLoadPath(lua_state, profile_path.string().c_str()); // Now call our function in a lua script if (0 != luaL_dofile(lua_state, profile_path.string().c_str())) { std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl; return false; } if (0 != luaL_dostring(lua_state, "return traffic_signal_penalty\n")) { std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl; return false; } speed_profile.traffic_signal_penalty = 10 * lua_tointeger(lua_state, -1); SimpleLogger().Write(logDEBUG) << "traffic_signal_penalty: " << speed_profile.traffic_signal_penalty; if (0 != luaL_dostring(lua_state, "return u_turn_penalty\n")) { std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl; return false; } speed_profile.u_turn_penalty = 10 * lua_tointeger(lua_state, -1); speed_profile.has_turn_penalty_function = lua_function_exists(lua_state, "turn_function"); return true; }
int main(int argc, char *argv[]) { try { LogPolicy::GetInstance().Unmute(); TIMER_START(preparing); TIMER_START(expansion); boost::filesystem::path config_file_path, input_path, restrictions_path, profile_path; unsigned int requested_num_threads; bool use_elevation; // declare a group of options that will be allowed only on command line boost::program_options::options_description generic_options("Options"); generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message")( "config,c", boost::program_options::value<boost::filesystem::path>(&config_file_path) ->default_value("contractor.ini"), "Path to a configuration file."); // declare a group of options that will be allowed both on command line and in config file boost::program_options::options_description config_options("Configuration"); config_options.add_options()( "restrictions,r", boost::program_options::value<boost::filesystem::path>(&restrictions_path), "Restrictions file in .osrm.restrictions format")( "profile,p", boost::program_options::value<boost::filesystem::path>(&profile_path) ->default_value("profile.lua"),"Path to LUA routing profile")( "elevation,e", boost::program_options::value<bool>(&use_elevation)->default_value(true), "Process node elevations")( "threads,t", boost::program_options::value<unsigned int>(&requested_num_threads)->default_value(tbb::task_scheduler_init::default_num_threads()), "Number of threads to use"); // hidden options, will be allowed both on command line and in config file, but will not be // shown to the user boost::program_options::options_description hidden_options("Hidden options"); hidden_options.add_options()( "input,i", boost::program_options::value<boost::filesystem::path>(&input_path), "Input file in .osm, .osm.bz2 or .osm.pbf format"); // positional option boost::program_options::positional_options_description positional_options; positional_options.add("input", 1); // combine above options for parsing boost::program_options::options_description cmdline_options; cmdline_options.add(generic_options).add(config_options).add(hidden_options); boost::program_options::options_description config_file_options; config_file_options.add(config_options).add(hidden_options); boost::program_options::options_description visible_options( "Usage: " + boost::filesystem::basename(argv[0]) + " <input.osrm> [options]"); visible_options.add(generic_options).add(config_options); // parse command line options boost::program_options::variables_map option_variables; boost::program_options::store(boost::program_options::command_line_parser(argc, argv) .options(cmdline_options) .positional(positional_options) .run(), option_variables); if (option_variables.count("version")) { SimpleLogger().Write() << g_GIT_DESCRIPTION; return 0; } if (option_variables.count("help")) { SimpleLogger().Write() << "\n" << visible_options; return 0; } boost::program_options::notify(option_variables); if (!option_variables.count("restrictions")) { restrictions_path = std::string(input_path.string() + ".restrictions"); } if (!option_variables.count("input")) { SimpleLogger().Write() << "\n" << visible_options; return 0; } if (!boost::filesystem::is_regular_file(input_path)) { SimpleLogger().Write(logWARNING) << "Input file " << input_path.string() << " not found!"; return 1; } if (!boost::filesystem::is_regular_file(profile_path)) { SimpleLogger().Write(logWARNING) << "Profile " << profile_path.string() << " not found!"; return 1; } if (1 > requested_num_threads) { SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger"; return 1; } const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads(); SimpleLogger().Write() << "Input file: " << input_path.filename().string(); SimpleLogger().Write() << "Restrictions file: " << restrictions_path.filename().string(); SimpleLogger().Write() << "Profile: " << profile_path.filename().string(); SimpleLogger().Write() << "Using elevation: " << use_elevation; SimpleLogger().Write() << "Threads: " << requested_num_threads; if (recommended_num_threads != requested_num_threads) { SimpleLogger().Write(logWARNING) << "The recommended number of threads is " << recommended_num_threads << "! This setting may have performance side-effects."; } tbb::task_scheduler_init init(requested_num_threads); LogPolicy::GetInstance().Unmute(); boost::filesystem::ifstream restriction_stream(restrictions_path, std::ios::binary); TurnRestriction restriction; FingerPrint fingerprint_loaded, fingerprint_orig; unsigned number_of_usable_restrictions = 0; restriction_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint)); if (!fingerprint_loaded.TestPrepare(fingerprint_orig)) { SimpleLogger().Write(logWARNING) << ".restrictions was prepared with different build.\n" "Reprocess to get rid of this warning."; } restriction_stream.read((char *)&number_of_usable_restrictions, sizeof(unsigned)); restriction_list.resize(number_of_usable_restrictions); if (number_of_usable_restrictions > 0) { restriction_stream.read((char *)&(restriction_list[0]), number_of_usable_restrictions * sizeof(TurnRestriction)); } restriction_stream.close(); boost::filesystem::ifstream in; in.open(input_path, std::ios::in | std::ios::binary); const std::string node_filename = input_path.string() + ".nodes"; const std::string edge_out = input_path.string() + ".edges"; const std::string geometry_filename = input_path.string() + ".geometry"; const std::string graphOut = input_path.string() + ".hsgr"; const std::string rtree_nodes_path = input_path.string() + ".ramIndex"; const std::string rtree_leafs_path = input_path.string() + ".fileIndex"; /*** Setup Scripting Environment ***/ // Create a new lua state lua_State *lua_state = luaL_newstate(); // Connect LuaBind to this lua state luabind::open(lua_state); // open utility libraries string library; luaL_openlibs(lua_state); // adjust lua load path luaAddScriptFolderToLoadPath(lua_state, profile_path.string().c_str()); // Now call our function in a lua script if (0 != luaL_dofile(lua_state, profile_path.string().c_str())) { std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl; return 1; } EdgeBasedGraphFactory::SpeedProfileProperties speed_profile; if (0 != luaL_dostring(lua_state, "return traffic_signal_penalty\n")) { std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl; return 1; } speed_profile.trafficSignalPenalty = 10 * lua_tointeger(lua_state, -1); SimpleLogger().Write(logDEBUG) << "traffic_signal_penalty: " << speed_profile.trafficSignalPenalty; if (0 != luaL_dostring(lua_state, "return u_turn_penalty\n")) { std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl; return 1; } speed_profile.uTurnPenalty = 10 * lua_tointeger(lua_state, -1); speed_profile.has_turn_penalty_function = lua_function_exists(lua_state, "turn_function"); #ifdef WIN32 #pragma message ("Memory consumption on Windows can be higher due to memory alignment") #else static_assert(sizeof(ImportEdge) == 20, "changing ImportEdge type has influence on memory consumption!"); #endif std::vector<ImportEdge> edge_list; NodeID number_of_node_based_nodes = readBinaryOSRMGraphFromStream(in, edge_list, barrier_node_list, traffic_light_list, &internal_to_external_node_map, restriction_list, use_elevation); in.close(); if (edge_list.empty()) { SimpleLogger().Write(logWARNING) << "The input data is empty, exiting."; return 1; } SimpleLogger().Write() << restriction_list.size() << " restrictions, " << barrier_node_list.size() << " bollard nodes, " << traffic_light_list.size() << " traffic lights"; /*** * Building an edge-expanded graph from node-based input and turn restrictions */ SimpleLogger().Write() << "Generating edge-expanded graph representation"; std::shared_ptr<NodeBasedDynamicGraph> node_based_graph = NodeBasedDynamicGraphFromImportEdges(number_of_node_based_nodes, edge_list); std::unique_ptr<RestrictionMap> restriction_map = std::unique_ptr<RestrictionMap>(new RestrictionMap(node_based_graph, restriction_list)); EdgeBasedGraphFactory *edge_based_graph_factor = new EdgeBasedGraphFactory(node_based_graph, std::move(restriction_map), barrier_node_list, traffic_light_list, internal_to_external_node_map, speed_profile); edge_list.clear(); edge_list.shrink_to_fit(); edge_based_graph_factor->Run(edge_out, geometry_filename, lua_state); restriction_list.clear(); restriction_list.shrink_to_fit(); barrier_node_list.clear(); barrier_node_list.shrink_to_fit(); traffic_light_list.clear(); traffic_light_list.shrink_to_fit(); unsigned number_of_edge_based_nodes = edge_based_graph_factor->GetNumberOfEdgeBasedNodes(); BOOST_ASSERT(number_of_edge_based_nodes != std::numeric_limits<unsigned>::max()); DeallocatingVector<EdgeBasedEdge> edgeBasedEdgeList; #ifndef WIN32 static_assert(sizeof(EdgeBasedEdge) == 16, "changing ImportEdge type has influence on memory consumption!"); #endif edge_based_graph_factor->GetEdgeBasedEdges(edgeBasedEdgeList); std::vector<EdgeBasedNode> node_based_edge_list; edge_based_graph_factor->GetEdgeBasedNodes(node_based_edge_list); delete edge_based_graph_factor; // TODO actually use scoping: Split this up in subfunctions node_based_graph.reset(); TIMER_STOP(expansion); // Building grid-like nearest-neighbor data structure SimpleLogger().Write() << "building r-tree ..."; StaticRTree<EdgeBasedNode> *rtree = new StaticRTree<EdgeBasedNode>(node_based_edge_list, rtree_nodes_path.c_str(), rtree_leafs_path.c_str(), internal_to_external_node_map); delete rtree; IteratorbasedCRC32<std::vector<EdgeBasedNode>> crc32; unsigned node_based_edge_list_CRC32 = crc32(node_based_edge_list.begin(), node_based_edge_list.end()); node_based_edge_list.clear(); node_based_edge_list.shrink_to_fit(); SimpleLogger().Write() << "CRC32: " << node_based_edge_list_CRC32; /*** * Writing info on original (node-based) nodes */ SimpleLogger().Write() << "writing node map ..."; boost::filesystem::ofstream node_stream(node_filename, std::ios::binary); const unsigned size_of_mapping = internal_to_external_node_map.size(); node_stream.write((char *)&size_of_mapping, sizeof(unsigned)); if (size_of_mapping > 0) { node_stream.write((char *)&(internal_to_external_node_map[0]), size_of_mapping * sizeof(NodeInfo)); } node_stream.close(); internal_to_external_node_map.clear(); internal_to_external_node_map.shrink_to_fit(); /*** * Contracting the edge-expanded graph */ SimpleLogger().Write() << "initializing contractor"; Contractor *contractor = new Contractor(number_of_edge_based_nodes, edgeBasedEdgeList); TIMER_START(contraction); contractor->Run(); TIMER_STOP(contraction); SimpleLogger().Write() << "Contraction took " << TIMER_SEC(contraction) << " sec"; DeallocatingVector<QueryEdge> contracted_edge_list; contractor->GetEdges(contracted_edge_list); delete contractor; /*** * Sorting contracted edges in a way that the static query graph can read some in in-place. */ std::sort(contracted_edge_list.begin(), contracted_edge_list.end()); unsigned max_used_node_id = 0; unsigned contracted_edge_count = contracted_edge_list.size(); SimpleLogger().Write() << "Serializing compacted graph of " << contracted_edge_count << " edges"; boost::filesystem::ofstream hsgr_output_stream(graphOut, std::ios::binary); hsgr_output_stream.write((char *)&fingerprint_orig, sizeof(FingerPrint)); for (const QueryEdge &edge : contracted_edge_list) { BOOST_ASSERT(UINT_MAX != edge.source); BOOST_ASSERT(UINT_MAX != edge.target); max_used_node_id = std::max(max_used_node_id, edge.source); max_used_node_id = std::max(max_used_node_id, edge.target); } SimpleLogger().Write(logDEBUG) << "input graph has " << number_of_edge_based_nodes << " nodes"; SimpleLogger().Write(logDEBUG) << "contracted graph has " << max_used_node_id << " nodes"; max_used_node_id += 1; std::vector<StaticGraph<EdgeData>::NodeArrayEntry> node_array; node_array.resize(number_of_edge_based_nodes + 1); SimpleLogger().Write() << "Building node array"; StaticGraph<EdgeData>::EdgeIterator edge = 0; StaticGraph<EdgeData>::EdgeIterator position = 0; StaticGraph<EdgeData>::EdgeIterator last_edge = edge; for (StaticGraph<EdgeData>::NodeIterator node = 0; node < max_used_node_id; ++node) { last_edge = edge; while ((edge < contracted_edge_count) && (contracted_edge_list[edge].source == node)) { ++edge; } node_array[node].first_edge = position; //=edge position += edge - last_edge; // remove } for (unsigned sentinel_counter = max_used_node_id; sentinel_counter != node_array.size(); ++sentinel_counter) { // sentinel element, guarded against underflow node_array[sentinel_counter].first_edge = contracted_edge_count; } unsigned node_array_size = node_array.size(); // serialize crc32, aka checksum hsgr_output_stream.write((char *)&node_based_edge_list_CRC32, sizeof(unsigned)); // serialize number of nodes hsgr_output_stream.write((char *)&node_array_size, sizeof(unsigned)); // serialize number of edges hsgr_output_stream.write((char *)&contracted_edge_count, sizeof(unsigned)); // serialize all nodes if (node_array_size > 0) { hsgr_output_stream.write((char *)&node_array[0], sizeof(StaticGraph<EdgeData>::NodeArrayEntry) * node_array_size); } // serialize all edges SimpleLogger().Write() << "Building edge array"; edge = 0; int number_of_used_edges = 0; StaticGraph<EdgeData>::EdgeArrayEntry current_edge; for (unsigned edge = 0; edge < contracted_edge_list.size(); ++edge) { // no eigen loops BOOST_ASSERT(contracted_edge_list[edge].source != contracted_edge_list[edge].target); current_edge.target = contracted_edge_list[edge].target; current_edge.data = contracted_edge_list[edge].data; // every target needs to be valid BOOST_ASSERT(current_edge.target < max_used_node_id); #ifndef NDEBUG if (current_edge.data.distance <= 0) { SimpleLogger().Write(logWARNING) << "Edge: " << edge << ",source: " << contracted_edge_list[edge].source << ", target: " << contracted_edge_list[edge].target << ", dist: " << current_edge.data.distance; SimpleLogger().Write(logWARNING) << "Failed at adjacency list of node " << contracted_edge_list[edge].source << "/" << node_array.size() - 1; return 1; } #endif hsgr_output_stream.write((char *)¤t_edge, sizeof(StaticGraph<EdgeData>::EdgeArrayEntry)); ++number_of_used_edges; } hsgr_output_stream.close(); TIMER_STOP(preparing); SimpleLogger().Write() << "Preprocessing : " << TIMER_SEC(preparing) << " seconds"; SimpleLogger().Write() << "Expansion : " << (number_of_node_based_nodes / TIMER_SEC(expansion)) << " nodes/sec and " << (number_of_edge_based_nodes / TIMER_SEC(expansion)) << " edges/sec"; SimpleLogger().Write() << "Contraction: " << (number_of_edge_based_nodes / TIMER_SEC(contraction)) << " nodes/sec and " << number_of_used_edges / TIMER_SEC(contraction) << " edges/sec"; node_array.clear(); SimpleLogger().Write() << "finished preprocessing"; } catch (boost::program_options::too_many_positional_options_error &) { SimpleLogger().Write(logWARNING) << "Only one file can be specified"; return 1; } catch (boost::program_options::error &e) { SimpleLogger().Write(logWARNING) << e.what(); return 1; } catch (const std::exception &e) { SimpleLogger().Write(logWARNING) << "Exception occured: " << e.what() << std::endl; return 1; } return 0; }
ScriptingEnvironment::ScriptingEnvironment(const char * fileName) { SimpleLogger().Write() << "Using script " << fileName; // Create a new lua state for(int i = 0; i < omp_get_max_threads(); ++i) { luaStateVector.push_back(luaL_newstate()); } // Connect LuaBind to this lua state for all threads #pragma omp parallel { lua_State * myLuaState = getLuaStateForThreadID(omp_get_thread_num()); luabind::open(myLuaState); //open utility libraries string library; luaL_openlibs(myLuaState); luaAddScriptFolderToLoadPath( myLuaState, fileName ); // Add our function to the state's global scope luabind::module(myLuaState) [ luabind::def("print", LUA_print<std::string>), luabind::def("parseMaxspeed", parseMaxspeed), luabind::def("durationIsValid", durationIsValid), luabind::def("parseDuration", parseDuration) ]; luabind::module(myLuaState) [ luabind::class_<HashTable<std::string, std::string> >("keyVals") .def("Add", &HashTable<std::string, std::string>::Add) .def("Find", &HashTable<std::string, std::string>::Find) .def("Holds", &HashTable<std::string, std::string>::Holds) ]; luabind::module(myLuaState) [ luabind::class_<ImportNode>("Node") .def(luabind::constructor<>()) .def_readwrite("lat", &ImportNode::lat) .def_readwrite("lon", &ImportNode::lon) .def_readwrite("id", &ImportNode::id) .def_readwrite("bollard", &ImportNode::bollard) .def_readwrite("traffic_light", &ImportNode::trafficLight) .def_readwrite("tags", &ImportNode::keyVals) ]; luabind::module(myLuaState) [ luabind::class_<ExtractionWay>("Way") .def(luabind::constructor<>()) .def_readwrite("name", &ExtractionWay::name) .def_readwrite("speed", &ExtractionWay::speed) .def_readwrite("backward_speed", &ExtractionWay::backward_speed) .def_readwrite("duration", &ExtractionWay::duration) .def_readwrite("type", &ExtractionWay::type) .def_readwrite("access", &ExtractionWay::access) .def_readwrite("roundabout", &ExtractionWay::roundabout) .def_readwrite("is_access_restricted", &ExtractionWay::isAccessRestricted) .def_readwrite("ignore_in_grid", &ExtractionWay::ignoreInGrid) .def_readwrite("tags", &ExtractionWay::keyVals) .def_readwrite("direction", &ExtractionWay::direction) .enum_("constants") [ luabind::value("notSure", 0), luabind::value("oneway", 1), luabind::value("bidirectional", 2), luabind::value("opposite", 3) ] ]; luabind::module(myLuaState) [ luabind::class_<std::vector<std::string> >("vector") .def("Add", &std::vector<std::string>::push_back) ]; if(0 != luaL_dofile(myLuaState, fileName) ) { throw OSRMException("ERROR occured in scripting block"); } } }