Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
b7b0665
valid time checking for zonal relations
robfitzgerald Apr 14, 2026
e5b5940
rename multimodal mapping -> categorical mapping
robfitzgerald Apr 14, 2026
b0a72fc
implement gtfs-flex traversal model
robfitzgerald Apr 15, 2026
3ab91b9
fmt
robfitzgerald Apr 15, 2026
851a924
move ops to higher shared location
robfitzgerald Apr 15, 2026
a71e3ec
fix elided lifetime
robfitzgerald Apr 15, 2026
5fffed7
update how we test if src_zone_id is set
robfitzgerald Apr 15, 2026
21b5a8e
reference leading compass branch with modified constraint model signa…
robfitzgerald Apr 15, 2026
1914d7a
reference leading compass branch with modified constraint model signa…
robfitzgerald Apr 15, 2026
e2fcd7e
complete flex constraint model
robfitzgerald Apr 15, 2026
ebe0f3d
clippy
robfitzgerald Apr 15, 2026
1835d36
rge branch 'main' into rjf/gtfs-flex-continued
robfitzgerald Apr 15, 2026
b2e20e7
fmt
robfitzgerald Apr 15, 2026
aaf96b6
wire in gtfs flex
robfitzgerald Apr 16, 2026
f5f6ff6
typo in variable name
robfitzgerald Apr 16, 2026
b5fd09a
more robust zonal relations
robfitzgerald Apr 16, 2026
e2c4e06
remove unused import
robfitzgerald Apr 16, 2026
96af823
prefer Feature "id" field for ZoneId data source
robfitzgerald Apr 16, 2026
d03e4f8
should be signed int
robfitzgerald Apr 16, 2026
15d579f
display implementation for config + debugging with display
robfitzgerald Apr 20, 2026
67f8939
incorrect method for "adding" vs "setting" seconds on time
robfitzgerald Apr 21, 2026
0a5dbf5
debug gtfs-flex modeling
robfitzgerald Apr 21, 2026
4bc3720
clippy
robfitzgerald Apr 21, 2026
8c90077
cleanup
robfitzgerald Apr 21, 2026
44fcb60
capture all fields, remove underscored typo
robfitzgerald Apr 22, 2026
78e12e1
deal with optional Stop field due to GTFS-Flex lib feature
robfitzgerald Apr 23, 2026
7c50d61
correct handling of AgencyId, leveraging forked gtfs-structures library
robfitzgerald Apr 23, 2026
785ad4e
remove unused
robfitzgerald Apr 23, 2026
3ef2165
clippy
robfitzgerald Apr 23, 2026
6faab27
cleanup comments + redundant feed name op
robfitzgerald Apr 23, 2026
591ba8c
Merge branch 'release/v0.3.0' into rjf/gtfs-flex-continued
robfitzgerald May 6, 2026
1df04c9
renamed type
robfitzgerald May 6, 2026
18e10e4
renamed value
robfitzgerald May 6, 2026
2cf0b87
renamed type
robfitzgerald May 6, 2026
3399473
Merge branch 'main' into rjf/gtfs-flex-continued
robfitzgerald May 6, 2026
6aea0ff
wire in fully-qualified ids into generated datasets
robfitzgerald May 7, 2026
b978216
fmt
robfitzgerald May 7, 2026
43ca11b
flex files example
robfitzgerald May 7, 2026
f286755
queries intersecting with the flex example study region
robfitzgerald May 7, 2026
c9ae623
update readme for run instructions
robfitzgerald May 7, 2026
85c7d54
clippy
robfitzgerald May 7, 2026
f2fefce
Merge branch 'main' into rjf/gtfs-flex-continued
robfitzgerald May 19, 2026
241df91
write/read GTFS-Flex data to/from flat files
robfitzgerald May 19, 2026
39dad27
Merge branch 'main' into rjf/gtfs-flex-continued
robfitzgerald May 26, 2026
3be56f1
fmt
robfitzgerald May 26, 2026
91969ef
clippy
robfitzgerald May 26, 2026
268f5ed
clippy warnings
robfitzgerald May 26, 2026
70543b7
config update app for gtfs-flex
robfitzgerald May 26, 2026
309badd
clippy
robfitzgerald May 26, 2026
10f19b6
bug fixes in config edits
robfitzgerald May 29, 2026
28cd697
update readme with test case
robfitzgerald May 29, 2026
dd757d8
gtfs-flex test case
robfitzgerald May 29, 2026
bc63266
clippy
robfitzgerald May 29, 2026
91279b3
executable
robfitzgerald May 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ geo-buffer = "0.2.0"
geo-traits = "0.3.0"
geo-types = "=0.7.19"
geozero = { version = "0.14.0", features = ["with-geo", "with-wkb", "with-wkt", "with-geojson"] }
gtfs-structures = "0.43.0"
gtfs-structures = { git = "https://github.com/robfitzgerald/gtfs-structure", branch = "rjf/135-gtfs-flex", features = ["gtfs-flex"] }
h3o = { version = "0.9.4", features = ["serde", "geo"] }
hex = "0.4.3"
humantime = "2.3.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@ use std::{collections::HashMap, fmt::Debug, path::Path};
/// can be used to index a Vec<T>.
///
#[derive(Clone, Debug)]
pub struct MultimodalMapping<T: Clone + Debug, U: Clone + Debug> {
pub struct CategoricalMapping<T: Clone + Debug, U: Clone + Debug> {
cat_to_label: HashMap<T, U>,
label_to_cat: Vec<T>,
}

/// a common type of multimodal mapping which maps strings to i64 values.
/// categories begin from zero. negative values denote an empty class label (None case).
pub type MultimodalStateMapping = MultimodalMapping<String, i64>;
/// a common instance of categorical mapping which maps strings to i64 values to be
/// stored in a Compass state vector. categories begin from zero. negative values denote
/// an empty class label (None case).
pub type CategoricalStateMapping = CategoricalMapping<String, i64>;

/// A trait for types that can be used as categorical identifiers
#[allow(dead_code)]
Expand All @@ -41,7 +42,7 @@ impl<U> IndexType for U where
{
}

impl MultimodalStateMapping {
impl CategoricalStateMapping {
pub fn from_enumerated_category_file(filepath: &Path) -> Result<Self, StateModelError> {
let contents = read_utils::read_raw_file(filepath, read_decoders::string, None, None)
.map_err(|e| {
Expand All @@ -50,18 +51,18 @@ impl MultimodalStateMapping {
filepath.to_string_lossy()
))
})?;
MultimodalMapping::new(&contents)
CategoricalMapping::new(&contents)
}
}

impl<T, U> MultimodalMapping<T, U>
impl<T, U> CategoricalMapping<T, U>
where
T: Eq + std::hash::Hash + Clone + Debug,
U: Eq + std::hash::Hash + Clone + Copy + TryFrom<usize> + TryInto<usize> + PartialOrd + Debug,
{
/// create an empty mapping
pub fn empty() -> Self {
MultimodalMapping {
CategoricalMapping {
cat_to_label: HashMap::new(),
label_to_cat: Vec::new(),
}
Expand Down
6 changes: 3 additions & 3 deletions rust/bambam-core/src/model/state/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
mod categorical_mapping;
pub mod fieldname;
mod multimodal_mapping;
pub mod multimodal_state_ops;
pub mod variable;

pub use multimodal_mapping::MultimodalMapping;
pub use multimodal_mapping::MultimodalStateMapping;
pub use categorical_mapping::CategoricalMapping;
pub use categorical_mapping::CategoricalStateMapping;
/// trip legs are enumerated starting from 0 to support zero-based indexing arithmetic.
pub type LegIdx = u64;

Expand Down
16 changes: 8 additions & 8 deletions rust/bambam-core/src/model/state/multimodal_state_ops.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::num::NonZeroU64;

use crate::model::state::{LegIdx, MultimodalStateMapping};
use crate::model::state::{CategoricalStateMapping, LegIdx};
use routee_compass_core::model::state::{StateModel, StateModelError, StateVariable};
use serde_json::json;
use uom::si::f64::{Energy, Length, Time};
Expand Down Expand Up @@ -31,7 +31,7 @@ pub fn get_active_leg_mode<'a>(
state: &[StateVariable],
state_model: &StateModel,
max_trip_legs: NonZeroU64,
mode_to_state: &'a MultimodalStateMapping,
mode_to_state: &'a CategoricalStateMapping,
) -> Result<Option<&'a str>, StateModelError> {
match get_active_leg_idx(state, state_model)? {
None => Ok(None),
Expand Down Expand Up @@ -68,7 +68,7 @@ pub fn appending_edge_mode_is_valid(
state_model: &StateModel,
leg_mode: &str,
max_trip_legs: NonZeroU64,
mode_to_state: &MultimodalStateMapping,
mode_to_state: &CategoricalStateMapping,
) -> Result<bool, StateModelError> {
// simulate a mode transition if the incoming edge has a different mode than the trip's active mode
let active_mode = get_active_leg_mode(state, state_model, max_trip_legs, mode_to_state)
Expand Down Expand Up @@ -127,7 +127,7 @@ pub fn get_existing_leg_mode<'a>(
leg_idx: LegIdx,
state_model: &StateModel,
max_trip_legs: NonZeroU64,
mode_to_state: &'a MultimodalStateMapping,
mode_to_state: &'a CategoricalStateMapping,
) -> Result<&'a str, StateModelError> {
let label_opt = get_leg_mode_label(state, leg_idx, state_model, max_trip_legs)?;
match label_opt {
Expand Down Expand Up @@ -176,7 +176,7 @@ pub fn get_leg_route_id<'a>(
state: &[StateVariable],
leg_idx: LegIdx,
state_model: &StateModel,
route_id_mapping: &'a MultimodalStateMapping,
route_id_mapping: &'a CategoricalStateMapping,
) -> Result<Option<&'a String>, StateModelError> {
let name = fieldname::leg_route_id_fieldname(leg_idx);
let route_id_label = state_model.get_custom_i64(state, &name)?;
Expand Down Expand Up @@ -230,7 +230,7 @@ pub fn get_mode_sequence(
state: &[StateVariable],
state_model: &StateModel,
max_trip_legs: NonZeroU64,
mode_to_state: &MultimodalStateMapping,
mode_to_state: &CategoricalStateMapping,
) -> Result<Vec<String>, StateModelError> {
let mut modes: Vec<String> = vec![];
let mut leg_idx = 0;
Expand Down Expand Up @@ -280,7 +280,7 @@ pub fn set_leg_mode(
leg_idx: LegIdx,
mode: &str,
state_model: &StateModel,
mode_to_state: &MultimodalStateMapping,
mode_to_state: &CategoricalStateMapping,
) -> Result<(), StateModelError> {
let mode_label = mode_to_state.get_label(mode).ok_or_else(|| {
StateModelError::RuntimeError(format!("mode mapping has no entry for '{mode}' mode"))
Expand All @@ -296,7 +296,7 @@ pub fn set_leg_route_id(
leg_idx: LegIdx,
route_id: &str,
state_model: &StateModel,
route_id_to_state: &MultimodalStateMapping,
route_id_to_state: &CategoricalStateMapping,
) -> Result<(), StateModelError> {
let route_id_label = route_id_to_state.get_label(route_id).ok_or_else(|| {
StateModelError::RuntimeError(format!(
Expand Down
15 changes: 10 additions & 5 deletions rust/bambam-core/src/model/state/variable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@ use uom::{
ConstZero,
};

/// config value representing an empty LegIdx, Mode, or RouteId.
pub const EMPTY: CustomVariableConfig = CustomVariableConfig::SignedInteger { initial: -1 };
/// value used to model emptiness for categoricals.
pub const EMPTY_CATEGORICAL_VALUE: i64 = -1;

/// config value representing an empty initial categorical value.
pub const EMPTY_VARIABLE_CONFIG: CustomVariableConfig = CustomVariableConfig::SignedInteger {
initial: EMPTY_CATEGORICAL_VALUE,
};

pub fn active_leg_input_feature() -> InputFeature {
InputFeature::Custom {
Expand All @@ -22,7 +27,7 @@ pub fn active_leg_input_feature() -> InputFeature {
pub fn active_leg_variable_config() -> StateVariableConfig {
StateVariableConfig::Custom {
custom_type: "ActiveLeg".to_string(),
value: EMPTY,
value: EMPTY_VARIABLE_CONFIG,
accumulator: true,
}
}
Expand All @@ -38,7 +43,7 @@ pub fn leg_mode_input_feature(leg_idx: LegIdx) -> InputFeature {
pub fn leg_mode_variable_config() -> StateVariableConfig {
StateVariableConfig::Custom {
custom_type: "Mode".to_string(),
value: EMPTY,
value: EMPTY_VARIABLE_CONFIG,
accumulator: true,
}
}
Expand Down Expand Up @@ -75,7 +80,7 @@ pub fn route_id_input_feature() -> InputFeature {
pub fn route_id_variable_config() -> StateVariableConfig {
StateVariableConfig::Custom {
custom_type: "RouteId".to_string(),
value: EMPTY,
value: EMPTY_VARIABLE_CONFIG,
accumulator: true,
}
}
10 changes: 4 additions & 6 deletions rust/bambam-gtfs-flex/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,24 @@ description = "Simple GTFS-Flex scanner"
repository = "https://github.com/NREL/bambam"
readme = "README.md"

[features]
default = ["type4"]
type4 = ["dep:gtfs-structures"]

[dependencies]
bambam-core = { version = "0.3.1", path = "../bambam-core" }
chrono = { workspace = true }
clap = { workspace = true }
csv = { workspace = true }
flate2 = { workspace = true }
geo = { workspace = true }
geo-types = { workspace = true }
geozero = { workspace = true }
gtfs-structures = { workspace = true, optional = true }
gtfs-structures = { workspace = true }
kdam = { workspace = true }
log = { workspace = true }
ordered-float = { workspace = true }
routee-compass-core = { workspace = true }
regex = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
skiplist = { workspace = true }
thiserror = { workspace = true }
uom = { workspace = true }
zip = { workspace = true }
# No external dependencies needed for the simple version
14 changes: 7 additions & 7 deletions rust/bambam-gtfs-flex/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# bambam-gtfs-flex
A set of extensions that enable On-Demand Transit modeling in BAMBAM using [GTFS-Flex](https://gtfs.org/community/extensions/flex/) datasets.

## run example

find a working example at [script/bambam_gtfs_flex_test.sh](/script/bambam_gtfs_flex_test.sh).

## GTFS Flex Service Types

We have observed four types of services:
Expand Down Expand Up @@ -54,14 +58,10 @@ To process GTFS Flex feeds, you can use the provided command-line interface (CLI
3. **Run the CLI Tool**
Use the following command to process a GTFS Flex feed:
```bash
./target/release/bambam-gtfs-flex process-feeds ./src/test/assets 20240903 valid_zone.csv
```
If you want to process GTFS-Flex feeds without completing `cargo build --release` in Step 2, you can simply use the following command:
```bash
cd rust/bambam-gtfs-flex
cargo run -- process-feeds ./src/test/assets 20240903
RUST_LOG=info ./rust/target/release/bambam-gtfs-flex import rust/bambam-gtfs-flex/src/test/assets/flex out/flex-test 20240903
```
Replace `./src/test/assets` with the path to the folder where your GTFS-Flex feeds (.zip files) are located, `20240903` with the desired date in `YYYYMMDD` format for which you want to process the feeds, and `valid_zones.csv` (optional) with the name of the output CSV file, which will be written to the GTFS-Flex feeds directory.

Replace `rust/bambam-gtfs-flex/src/test/assets/flex` with the path to the folder where your GTFS-Flex feeds (.zip files) are located, `20240903` with the desired date in `YYYYMMDD` format for which you want to process the feeds, and `out/flex-test` with the output directory.

4. **Verify Output**
After processing, the output directory will contain the processed valid zone CSV for the requested date, ready for use in BAMBAM.
Expand Down
91 changes: 0 additions & 91 deletions rust/bambam-gtfs-flex/src/agency.rs

This file was deleted.

Loading
Loading