rustsim 0.0.1

High-performance agent-based modelling engine - top-level orchestration crate
Documentation
//! End-to-end multimodal commute example.
//!
//! Demonstrates the production integration seam across `rustsim-mobility`,
//! `rustsim-traffic`, `rustsim-transit`, `rustsim-vehicle`, and
//! `rustsim-crowd`.

use rustsim::prelude::{AllowedModes, LinkClass, LinkProperties, TravelMode};
use rustsim::rustsim_mobility::prelude::*;
use rustsim::rustsim_traffic::{TransportLinkMetadata, TransportLinkOps, TransportLinkSpace};
use rustsim::rustsim_transit::{Boarding, Route, Schedule, Stop, TransitVehicle, Waiter};
use rustsim::rustsim_vehicle::{idm, Vehicle, VehicleModel};

fn main() {
    let mut network = TransportLinkSpace::new();
    let home = network.add_node();
    let stop_a = network.add_node();
    let stop_b = network.add_node();
    let work = network.add_node();

    let (walk_geom, walk_props) = LinkProperties::pedestrian(80.0, 3.0).unwrap();
    let walk_to_stop = network
        .add_link(home, stop_a, walk_geom, walk_props)
        .unwrap();
    let (bus_geom, bus_props) = LinkProperties::urban(600.0, 40.0, 1).unwrap();
    let bus_link = network
        .add_link(stop_a, stop_b, bus_geom, bus_props)
        .unwrap();
    let (walk_out_geom, walk_out_props) = LinkProperties::pedestrian(80.0, 3.0).unwrap();
    let walk_to_work = network
        .add_link(stop_b, work, walk_out_geom, walk_out_props)
        .unwrap();
    let (direct_geom, direct_props) = LinkProperties::pedestrian(1_200.0, 3.0).unwrap();
    let direct_walk = network
        .add_link(home, work, direct_geom, direct_props)
        .unwrap();

    let metadata = vec![
        TransportLinkMetadata::new(
            walk_to_stop,
            home,
            stop_a,
            LinkClass::Walkway,
            AllowedModes::pedestrian_only(),
        ),
        TransportLinkMetadata::new(
            bus_link,
            stop_a,
            stop_b,
            LinkClass::Transitway,
            AllowedModes::none().with_mode(TravelMode::Transit),
        ),
        TransportLinkMetadata::new(
            walk_to_work,
            stop_b,
            work,
            LinkClass::Walkway,
            AllowedModes::pedestrian_only(),
        ),
        TransportLinkMetadata::new(
            direct_walk,
            home,
            work,
            LinkClass::Walkway,
            AllowedModes::pedestrian_only(),
        ),
    ];

    let graph = ModalGraph::from_transport_links(&network, metadata).unwrap();
    let route = shortest_path(
        &graph,
        home as u64,
        work as u64,
        AllowedModes::pedestrian_only().with_mode(TravelMode::Transit),
    )
    .unwrap();
    println!(
        "nodes={:?}, total_cost_s={:.1}",
        route.nodes, route.total_cost
    );

    let stop_a_def = Stop::at_ground(10, "Home stop", 80.0, 0.0, 80);
    let stop_b_def = Stop::at_ground(20, "Work stop", 680.0, 0.0, 80);
    let transit_route = Route::new(
        5,
        "Blue",
        vec![stop_a_def.id, stop_b_def.id],
        vec![network.link_free_flow_time(bus_link)],
        Schedule::fixed_headway(300.0),
    );

    let plan = TripPlan {
        id: 1,
        legs: vec![
            Leg::Walk {
                from: Waypoint::ground(0.0, 0.0),
                to: Waypoint::ground(stop_a_def.pos[0], stop_a_def.pos[1]),
            },
            Leg::Transit {
                route: transit_route.id,
                board_at: stop_a_def.id,
                alight_at: stop_b_def.id,
            },
            Leg::Walk {
                from: Waypoint::ground(stop_b_def.pos[0], stop_b_def.pos[1]),
                to: Waypoint::ground(760.0, 0.0),
            },
        ],
    };

    let traveller_id = 42;
    let controller = ModeController;
    let mut traveller = TravellerContext::new(traveller_id);
    controller.enter_current_leg(&mut traveller, &plan);
    controller.complete_leg(&mut traveller, &plan);

    let mut queue = Boarding::new();
    let waiter = Waiter {
        passenger: traveller_id,
        destination: stop_b_def.id,
        arrived_at: 0.0,
    };
    assert!(CapacityStopQueuePolicy.can_enqueue(&stop_a_def, &queue, &waiter));
    queue.enqueue(waiter);
    assert_eq!(
        ScheduledDispatchPolicy.decide(DispatchContext::new(&transit_route, 0.0)),
        DispatchDecision::Dispatch { departure_s: 0.0 }
    );
    let mut service = TransitVehicle::idle(99, transit_route.id, 30);
    let mut passenger_destinations = Vec::new();
    let boarded = queue.board_vehicle_with_policy(
        &mut service,
        &transit_route.stops,
        &mut passenger_destinations,
        &FifoBoardingPolicy::unlimited(),
    );
    let dwell = LinearDwellPolicy::default().dwell_time(0, boarded.boarded);
    controller.board_transit(&mut traveller, service.id, stop_b_def.id);

    network
        .add_agent_to_link(service.id, bus_link, 0.0)
        .unwrap();
    let speed = network
        .agent_speed_with_policy(service.id, &FifoGapPolicy::default())
        .unwrap();
    network.advance_agent(service.id, speed * 10.0).unwrap();
    let bus = Vehicle {
        pos: [stop_a_def.pos[0], stop_a_def.pos[1]],
        speed,
        ..Vehicle::default_bus()
    };
    let mut bus_platoon = [bus];
    rustsim::rustsim_vehicle::IntelligentDriverModel.step(
        &mut bus_platoon,
        &idm::Params::default(),
        1.0,
    );
    let bus = bus_platoon[0];

    let pedestrian = rustsim::rustsim_crowd::Pedestrian::new(
        [stop_a_def.pos[0] - 2.0, 0.0],
        [1.0, 0.0],
        0.25,
        1.3,
        [stop_a_def.pos[0], 0.0],
    );
    let ped_obstacle = PedestrianObstacle::ground(traveller_id, &pedestrian).snapshot();
    let bus_obstacle = VehicleObstacle::ground(service.id, &bus).snapshot();

    let alighted = service.alight_at(stop_b_def.id, &passenger_destinations);
    controller.alight_transit(&mut traveller, &plan);
    controller.complete_leg(&mut traveller, &plan);

    println!(
        "boarded={}, dwell_s={:.1}, alighted={}, bus_x={:.1}, ped_radius={:.2}, bus_radius={:.2}, final_state={:?}",
        boarded.boarded,
        dwell.total,
        alighted.len(),
        bus.pos[0],
        ped_obstacle.radius,
        bus_obstacle.radius,
        traveller.state
    );

    assert_eq!(traveller.state, ModeState::Finished);
}