From 20b6e112adbf4eb8707b20cbd59bb71f6890f23e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20G=C3=BCndling?= Date: Fri, 4 Aug 2023 09:47:30 +0200 Subject: [PATCH 1/5] wip --- src/rt/gtfsrt_resolve_run.cc | 37 ++++++++++++++++-- test/rt/gtfsrt_resolve_trip_test.cc | 60 +++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 3 deletions(-) diff --git a/src/rt/gtfsrt_resolve_run.cc b/src/rt/gtfsrt_resolve_run.cc index e356e12d..3590bdea 100644 --- a/src/rt/gtfsrt_resolve_run.cc +++ b/src/rt/gtfsrt_resolve_run.cc @@ -39,27 +39,50 @@ void resolve_static(date::sys_days const today, : std::nullopt; auto const id_matches = [&](trip_id_idx_t const t_id_idx) { + std::cout << "MATCH: " << tt.trip_id_strings_[t_id_idx].view() + << " == " << trip_id << ": " << std::boolalpha + << (tt.trip_id_strings_[t_id_idx].view() == trip_id) << "\n"; return tt.trip_id_src_[t_id_idx] == src && tt.trip_id_strings_[t_id_idx].view() == trip_id; }; + if (lb == end(tt.trip_id_to_idx_) || !id_matches(lb->first)) { + std::cout << "ID MISMATCH\n"; + return; + } + for (auto i = lb; i != end(tt.trip_id_to_idx_) && id_matches(i->first); ++i) { + std::cout << "TRIP TRANSPORTS: " + << tt.trip_transport_ranges_[i->second].size() << "\n"; for (auto const [t, stop_range] : tt.trip_transport_ranges_[i->second]) { auto const gtfs_static_dep = tt.event_mam(t, stop_range.from_, event_type::kDep).as_duration() + tt.transport_first_dep_offset_[t]; - if (start_time.has_value() && gtfs_static_dep != start_time) { + if (start_time.has_value() && gtfs_static_dep != *start_time) { + std::cout << "TIME MISMATCH: gtfs_static_dep=" << gtfs_static_dep + << ", start_time=" << *start_time << "\n"; continue; } + auto const utc_dep = + tt.event_mam(t, stop_range.from_, event_type::kDep).as_duration(); auto const day_offset = date::days{static_cast(std::floor( - static_cast(tt.transport_first_dep_offset_[t].count()) / + static_cast(utc_dep.count() - gtfs_static_dep.count()) / 1440U))}; - auto const day_idx = ((start_date.has_value() ? *start_date : today) + + std::cout << "offset=" << utc_dep.count() - gtfs_static_dep.count() + << "\n"; + std::cout << "utc_dep=" << utc_dep.count() / 60 << ":" + << utc_dep.count() % 60 << "\n"; + std::cout << "gtfs_static_dep=" << (gtfs_static_dep.count() / 60) << ":" + << (gtfs_static_dep.count() % 60) << "\n"; + std::cout << "day_offset: " << gtfs_static_dep.count() << " " + << utc_dep.count() << " " << day_offset << "\n"; + auto const day_idx = ((start_date.has_value() ? *start_date : today) - day_offset - tt.internal_interval_days().from_) .count(); if (day_idx > kMaxDays || day_idx < 0) { + std::cout << "DAY OUT OF RANGE: " << day_idx << "\n"; continue; } @@ -68,7 +91,15 @@ void resolve_static(date::sys_days const today, r.t_ = transport{t, day_idx_t{day_idx}}; r.stop_range_ = stop_range; trip = i->second; + return; } + + auto const day = + tt.internal_interval_days().from_ + day_idx * std::chrono::days{1}; + std::cout << "DAY INACTIVE: " << day << " [=day_idx " << day_idx + << "], active=" + << day_list{traffic_days, tt.internal_interval_days().from_} + << "\n"; } } } diff --git a/test/rt/gtfsrt_resolve_trip_test.cc b/test/rt/gtfsrt_resolve_trip_test.cc index 3c09e76e..33325695 100644 --- a/test/rt/gtfsrt_resolve_trip_test.cc +++ b/test/rt/gtfsrt_resolve_trip_test.cc @@ -3,6 +3,7 @@ #include "nigiri/loader/gtfs/files.h" #include "nigiri/loader/gtfs/load_timetable.h" #include "nigiri/loader/init_finish.h" +#include "nigiri/rt/create_rt_timetable.h" #include "nigiri/rt/frun.h" #include "nigiri/rt/gtfsrt_resolve_run.h" #include "nigiri/rt/gtfsrt_update.h" @@ -109,6 +110,64 @@ TEST(rt, gtfsrt_resolve_static_trip) { } } +mem_dir miami_test_files() { + return mem_dir::read(R"( +# agency.txt +agency_id,agency_name,agency_url,agency_timezone,agency_lang +Miami-Dade Transit,Miami-Dade Transit,http://www.miamidade.gov/transit,America/New_York,en + +# stops.txt +stop_id,stop_name,stop_lat,stop_lon,stop_code,stop_desc +1,Quail Roost Dr & SW 115 Ave,25.592450,-80.377950,115AQRSN,SW 107TH AVE & SW 112TH ST +3614,SW 107TH AVE @ SW 128TH ST,25.591810,-80.379840,QRSD17A3, +3213,SW 117 AV @ QUAIL ROOST DR,25.590330,-80.380730,C117QUA4, + +# routes.txt +agency_id,route_id,route_short_name,route_long_name,route_type,route_color,route_text_color,eligibility_restricted +Miami-Dade Transit,27757,1,SO.MIAMI HTS-PERRINE VIA SOUTHLAND,3,FF00FF,FFFFFF,-999 + +# trips.txt +route_id,trip_id,service_id,trip_headsign,direction_id,block_id,shape_id,drt_advance_book_min,peak_offpeak +27757,5456914,1,1 - SW 168 St,0,1484970,196385,0.0,0 + +# stop_times.txt +trip_id,stop_id,arrival_time,departure_time,timepoint,stop_sequence,shape_dist_traveled,continuous_pickup,continuous_drop_off,start_service_area_radius,end_service_area_radius,departure_buffer +5456914,1,15:15:00,15:15:00,1,1,,-999,-999,-999.0,-999.0,0 +5456914,3614,15:15:35,15:15:35,0,2,0.1548,-999,-999,-999.0,-999.0,0 +5456914,3213,15:16:20,15:16:20,0,3,0.354,-999,-999,-999.0,-999.0,0 + +# calendar_dates.txt +service_id,date,exception_type +1,20230904,2 + +# calendar.txt +service_id,monday,tuesday,wednesday,thursday,friday,saturday,sunday,start_date,end_date +1,1,1,1,1,1,0,0,20230724,20231112 +)"); +} + +TEST(rt, resolve_tz) { + auto tt = timetable{}; + + tt.date_range_ = {date::sys_days{2023_y / August / 3}, + date::sys_days{2023_y / August / 4}}; + loader::register_special_stations(tt); + loader::gtfs::load_timetable({}, source_idx_t{0}, miami_test_files(), tt); + loader::finalize(tt); + + auto rtt = rt::create_rt_timetable(tt, date::sys_days{2023_y / August / 3}); + + transit_realtime::FeedMessage msg; + auto const entity = msg.add_entity(); + auto const td = entity->mutable_trip_update()->mutable_trip(); + td->set_start_date("20230803"); + td->set_trip_id("5456914"); + + auto const r = gtfsrt_resolve_run(date::sys_days{2023_y / August / 3}, tt, + rtt, source_idx_t{0U}, *td); + EXPECT_TRUE(r.first.valid()); +} + TEST(rt, gtfs_rt_update) { auto const to_unix = [](auto&& x) { return std::chrono::time_point_cast(x) @@ -162,6 +221,7 @@ TEST(rt, gtfs_rt_update) { rt::gtfsrt_resolve_run(date::sys_days{2019_y / May / 4}, tt, rtt, source_idx_t{0}, *td) .first}; + ASSERT_TRUE(fr.valid()); for (auto const [from, to] : utl::pairwise(fr)) { EXPECT_EQ(scheduled[i++], from.scheduled_time(nigiri::event_type::kDep)); EXPECT_EQ(scheduled[i++], to.scheduled_time(nigiri::event_type::kArr)); From 081a84e18b73d5f821941c72b5785f22e37f3891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20G=C3=BCndling?= Date: Sun, 6 Aug 2023 22:22:11 +0200 Subject: [PATCH 2/5] wip --- include/nigiri/loader/gtfs/local_to_utc.h | 2 +- include/nigiri/types.h | 5 +++ src/rt/gtfsrt_resolve_run.cc | 48 ++++++++--------------- test/rt/gtfsrt_resolve_trip_test.cc | 48 +++++++++++++++++------ 4 files changed, 60 insertions(+), 43 deletions(-) diff --git a/include/nigiri/loader/gtfs/local_to_utc.h b/include/nigiri/loader/gtfs/local_to_utc.h index c7b3db46..ed45d9bb 100644 --- a/include/nigiri/loader/gtfs/local_to_utc.h +++ b/include/nigiri/loader/gtfs/local_to_utc.h @@ -156,7 +156,7 @@ void expand_local_to_utc(trip_data const& trip_data, auto prev_key = conversion_key{date::days{2}, duration_t{-1}}; auto prev_it = utc_time_traffic_days.end(); for (auto day = gtfs_interval.from_; day != gtfs_interval.to_; - day += std::chrono::days{1}) { + day += date::days{1}) { auto const service_days = interval{day + first_day_offset, day + last_day_offset + date::days{1}}; if (!selection.overlaps(service_days)) { diff --git a/include/nigiri/types.h b/include/nigiri/types.h index 11b354bb..f3fced08 100644 --- a/include/nigiri/types.h +++ b/include/nigiri/types.h @@ -298,6 +298,11 @@ inline std::ostream& operator<<(std::ostream& out, << std::setw(2) << std::setfill('0') << minutes << '.' << days; } +inline std::ostream& operator<<(std::ostream& out, + nigiri::duration_t const& t) { + return out << std::chrono::duration_cast(t); +} + inline std::ostream& operator<<(std::ostream& out, nigiri::unixtime_t const& t) { date::to_stream(out, "%F %R", t); diff --git a/src/rt/gtfsrt_resolve_run.cc b/src/rt/gtfsrt_resolve_run.cc index 3590bdea..5edde028 100644 --- a/src/rt/gtfsrt_resolve_run.cc +++ b/src/rt/gtfsrt_resolve_run.cc @@ -12,6 +12,17 @@ namespace nigiri::rt { +template +T mod(T const a, T const b) { + return (b + (a % b)) % b; +} + +std::pair split(duration_t const i) { + auto const a = static_cast(std::round(i.count() / 1440.)); + auto const b = i.count() - a * 1440; + return {date::days{a}, duration_t{b}}; +} + void resolve_static(date::sys_days const today, timetable const& tt, source_idx_t const src, @@ -39,50 +50,32 @@ void resolve_static(date::sys_days const today, : std::nullopt; auto const id_matches = [&](trip_id_idx_t const t_id_idx) { - std::cout << "MATCH: " << tt.trip_id_strings_[t_id_idx].view() - << " == " << trip_id << ": " << std::boolalpha - << (tt.trip_id_strings_[t_id_idx].view() == trip_id) << "\n"; return tt.trip_id_src_[t_id_idx] == src && tt.trip_id_strings_[t_id_idx].view() == trip_id; }; if (lb == end(tt.trip_id_to_idx_) || !id_matches(lb->first)) { - std::cout << "ID MISMATCH\n"; return; } for (auto i = lb; i != end(tt.trip_id_to_idx_) && id_matches(i->first); ++i) { - std::cout << "TRIP TRANSPORTS: " - << tt.trip_transport_ranges_[i->second].size() << "\n"; for (auto const [t, stop_range] : tt.trip_transport_ranges_[i->second]) { + auto const o = tt.transport_first_dep_offset_[t]; auto const gtfs_static_dep = - tt.event_mam(t, stop_range.from_, event_type::kDep).as_duration() + - tt.transport_first_dep_offset_[t]; + tt.event_mam(t, stop_range.from_, event_type::kDep).as_duration() + o; if (start_time.has_value() && gtfs_static_dep != *start_time) { - std::cout << "TIME MISMATCH: gtfs_static_dep=" << gtfs_static_dep - << ", start_time=" << *start_time << "\n"; continue; } auto const utc_dep = tt.event_mam(t, stop_range.from_, event_type::kDep).as_duration(); - auto const day_offset = date::days{static_cast(std::floor( - static_cast(utc_dep.count() - gtfs_static_dep.count()) / - 1440U))}; - std::cout << "offset=" << utc_dep.count() - gtfs_static_dep.count() - << "\n"; - std::cout << "utc_dep=" << utc_dep.count() / 60 << ":" - << utc_dep.count() % 60 << "\n"; - std::cout << "gtfs_static_dep=" << (gtfs_static_dep.count() / 60) << ":" - << (gtfs_static_dep.count() % 60) << "\n"; - std::cout << "day_offset: " << gtfs_static_dep.count() << " " - << utc_dep.count() << " " << day_offset << "\n"; - auto const day_idx = ((start_date.has_value() ? *start_date : today) - - day_offset - tt.internal_interval_days().from_) + auto const [tz_offset_days, tz_offset_minutes] = + split(gtfs_static_dep - utc_dep); + auto const day_idx = ((start_date.has_value() ? *start_date : today) + + tz_offset_days - tt.internal_interval_days().from_) .count(); if (day_idx > kMaxDays || day_idx < 0) { - std::cout << "DAY OUT OF RANGE: " << day_idx << "\n"; continue; } @@ -93,13 +86,6 @@ void resolve_static(date::sys_days const today, trip = i->second; return; } - - auto const day = - tt.internal_interval_days().from_ + day_idx * std::chrono::days{1}; - std::cout << "DAY INACTIVE: " << day << " [=day_idx " << day_idx - << "], active=" - << day_list{traffic_days, tt.internal_interval_days().from_} - << "\n"; } } } diff --git a/test/rt/gtfsrt_resolve_trip_test.cc b/test/rt/gtfsrt_resolve_trip_test.cc index 33325695..b7a1b6c8 100644 --- a/test/rt/gtfsrt_resolve_trip_test.cc +++ b/test/rt/gtfsrt_resolve_trip_test.cc @@ -76,6 +76,13 @@ TEST(rt, gtfsrt_resolve_static_trip) { load_timetable({}, source_idx_t{0}, test_files(), tt); { // test start time >24:00:00 + + // first dep: + // 49:00 2019-05-03 GMT -02:00 + // -> 01:00.2 2019-05-03 GMT -02:00 + // -> 23:00.1 2019-05-03 UTC + // -> 23:00 2019-05-04 UTC + auto td = transit_realtime::TripDescriptor(); *td.mutable_start_time() = "49:00:00"; *td.mutable_start_date() = "20190503"; @@ -83,7 +90,7 @@ TEST(rt, gtfsrt_resolve_static_trip) { auto const [r, t] = rt::gtfsrt_resolve_run(date::sys_days{2019_y / May / 3}, tt, rtt, source_idx_t{0}, td); - ASSERT_TRUE(r.valid()); + EXPECT_TRUE(r.valid()); } { // test start time that's on the prev. day in UTC @@ -94,7 +101,7 @@ TEST(rt, gtfsrt_resolve_static_trip) { auto const [r, t] = rt::gtfsrt_resolve_run(date::sys_days{2019_y / May / 4}, tt, rtt, source_idx_t{0}, td); - ASSERT_TRUE(r.valid()); + EXPECT_TRUE(r.valid()); } { // test without start_time and start_date (assuming "today" as date) @@ -129,12 +136,16 @@ Miami-Dade Transit,27757,1,SO.MIAMI HTS-PERRINE VIA SOUTHLAND,3,FF00FF,FFFFFF,-9 # trips.txt route_id,trip_id,service_id,trip_headsign,direction_id,block_id,shape_id,drt_advance_book_min,peak_offpeak 27757,5456914,1,1 - SW 168 St,0,1484970,196385,0.0,0 +27757,5456915,1,1 - SW 168 St,0,1484970,196385,0.0,0 # stop_times.txt trip_id,stop_id,arrival_time,departure_time,timepoint,stop_sequence,shape_dist_traveled,continuous_pickup,continuous_drop_off,start_service_area_radius,end_service_area_radius,departure_buffer 5456914,1,15:15:00,15:15:00,1,1,,-999,-999,-999.0,-999.0,0 5456914,3614,15:15:35,15:15:35,0,2,0.1548,-999,-999,-999.0,-999.0,0 5456914,3213,15:16:20,15:16:20,0,3,0.354,-999,-999,-999.0,-999.0,0 +5456915,1,47:15:00,47:15:00,1,1,,-999,-999,-999.0,-999.0,0 +5456915,3614,47:15:35,47:15:35,0,2,0.1548,-999,-999,-999.0,-999.0,0 +5456915,3213,47:16:20,47:16:20,0,3,0.354,-999,-999,-999.0,-999.0,0 # calendar_dates.txt service_id,date,exception_type @@ -150,22 +161,37 @@ TEST(rt, resolve_tz) { auto tt = timetable{}; tt.date_range_ = {date::sys_days{2023_y / August / 3}, - date::sys_days{2023_y / August / 4}}; + date::sys_days{2023_y / August / 5}}; loader::register_special_stations(tt); loader::gtfs::load_timetable({}, source_idx_t{0}, miami_test_files(), tt); loader::finalize(tt); auto rtt = rt::create_rt_timetable(tt, date::sys_days{2023_y / August / 3}); - transit_realtime::FeedMessage msg; - auto const entity = msg.add_entity(); - auto const td = entity->mutable_trip_update()->mutable_trip(); - td->set_start_date("20230803"); - td->set_trip_id("5456914"); + { + auto td = transit_realtime::TripDescriptor(); + td.set_start_date("20230803"); + td.set_trip_id("5456914"); + + auto const r = gtfsrt_resolve_run(date::sys_days{2023_y / August / 3}, tt, + rtt, source_idx_t{0U}, td); + EXPECT_TRUE(r.first.valid()); + } - auto const r = gtfsrt_resolve_run(date::sys_days{2023_y / August / 3}, tt, - rtt, source_idx_t{0U}, *td); - EXPECT_TRUE(r.first.valid()); + { + // first dep: + // 47:00 2023-08-03 GMT +04:00 + // -> 23:00.1 2023-08-03 GMT +04:00 + // -> 03:00.2 2023-08-03 UTC + // -> 03:00 2023-08-05 UTC + auto td = transit_realtime::TripDescriptor(); + td.set_start_date("20230803"); + td.set_trip_id("5456915"); + + auto const r = gtfsrt_resolve_run(date::sys_days{2023_y / August / 3}, tt, + rtt, source_idx_t{0U}, td); + EXPECT_TRUE(r.first.valid()); + } } TEST(rt, gtfs_rt_update) { From 59362c6bd1eba349e29ee468369238db58f3e717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20G=C3=BCndling?= Date: Sun, 6 Aug 2023 22:23:21 +0200 Subject: [PATCH 3/5] wip --- src/rt/gtfsrt_resolve_run.cc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/rt/gtfsrt_resolve_run.cc b/src/rt/gtfsrt_resolve_run.cc index 5edde028..12260a48 100644 --- a/src/rt/gtfsrt_resolve_run.cc +++ b/src/rt/gtfsrt_resolve_run.cc @@ -12,11 +12,6 @@ namespace nigiri::rt { -template -T mod(T const a, T const b) { - return (b + (a % b)) % b; -} - std::pair split(duration_t const i) { auto const a = static_cast(std::round(i.count() / 1440.)); auto const b = i.count() - a * 1440; From 8c8b099585f109dc263e9e44663950451b30d195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20G=C3=BCndling?= Date: Sun, 6 Aug 2023 22:24:00 +0200 Subject: [PATCH 4/5] wip --- src/rt/gtfsrt_resolve_run.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/rt/gtfsrt_resolve_run.cc b/src/rt/gtfsrt_resolve_run.cc index 12260a48..f1f3e3eb 100644 --- a/src/rt/gtfsrt_resolve_run.cc +++ b/src/rt/gtfsrt_resolve_run.cc @@ -49,10 +49,6 @@ void resolve_static(date::sys_days const today, tt.trip_id_strings_[t_id_idx].view() == trip_id; }; - if (lb == end(tt.trip_id_to_idx_) || !id_matches(lb->first)) { - return; - } - for (auto i = lb; i != end(tt.trip_id_to_idx_) && id_matches(i->first); ++i) { for (auto const [t, stop_range] : tt.trip_transport_ranges_[i->second]) { auto const o = tt.transport_first_dep_offset_[t]; From e27f55924c573f454e6a68394dfd165460af6dbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20G=C3=BCndling?= Date: Sun, 6 Aug 2023 22:25:26 +0200 Subject: [PATCH 5/5] wip --- src/rt/gtfsrt_resolve_run.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/rt/gtfsrt_resolve_run.cc b/src/rt/gtfsrt_resolve_run.cc index f1f3e3eb..ba283e2f 100644 --- a/src/rt/gtfsrt_resolve_run.cc +++ b/src/rt/gtfsrt_resolve_run.cc @@ -61,10 +61,10 @@ void resolve_static(date::sys_days const today, auto const utc_dep = tt.event_mam(t, stop_range.from_, event_type::kDep).as_duration(); - auto const [tz_offset_days, tz_offset_minutes] = + auto const [day_offset, tz_offset_minutes] = split(gtfs_static_dep - utc_dep); auto const day_idx = ((start_date.has_value() ? *start_date : today) + - tz_offset_days - tt.internal_interval_days().from_) + day_offset - tt.internal_interval_days().from_) .count(); if (day_idx > kMaxDays || day_idx < 0) { continue; @@ -75,7 +75,6 @@ void resolve_static(date::sys_days const today, r.t_ = transport{t, day_idx_t{day_idx}}; r.stop_range_ = stop_range; trip = i->second; - return; } } }