Dynamic Configuration¶
Most of the time, we are not actually interested in just running a simulation that we've pre-configured in files on disk. Instead, we will want to load a simulation from pre-configured in files on disk, but then change a couple things before we run it. Perhaps we're debugging a new RM system, and want to just run a few iterations to see if it works. Or maybe we have a model mostly ready to go, but we want to modify a couple of RM system parameters, or change the level of demand, or just monkey around with the network schedule a bit.
We can do all of that and more, right here in Python, especially in a Jupyter notebook.
import passengersim as pax
pax.versions()
passengersim 0.59.dev9+ga3f6c1b98 passengersim.core 0.59.dev1+g671876c7d
Let's start by loading our demo model from its YAML files into a
PassengerSim Config object.
cfg = pax.Config.from_yaml(pax.demo_network("3MKT/08-untrunc-em"))
The cfg now holds the data that defines everything about the simulation that will be run,
including the carriers, RM systems, networks, ... everything. Before we use this config to
initialize a simulation, we can inspect and even modify it in Python. For example, let's take
a look at the flight legs in this network.
cfg.legs
[Leg(leg_id=None, carrier='AL1', fltno=101, orig='BOS', orig_timezone='America/New_York', dest='ORD', dest_timezone='America/Chicago', date=datetime.datetime(2020, 3, 1, 0, 0, tzinfo=datetime.timezone.utc), arr_day=0, dep_time=1583067600, dep_time_offset=-18000, arr_time=1583078400, arr_time_offset=-21600, time_adjusted=True, capacity=100, distance=863.7532821438833), Leg(leg_id=None, carrier='AL1', fltno=102, orig='BOS', orig_timezone='America/New_York', dest='ORD', dest_timezone='America/Chicago', date=datetime.datetime(2020, 3, 1, 0, 0, tzinfo=datetime.timezone.utc), arr_day=0, dep_time=1583089200, dep_time_offset=-18000, arr_time=1583100000, arr_time_offset=-21600, time_adjusted=True, capacity=100, distance=863.7532821438833), Leg(leg_id=None, carrier='AL2', fltno=201, orig='BOS', orig_timezone='America/New_York', dest='ORD', dest_timezone='America/Chicago', date=datetime.datetime(2020, 3, 1, 0, 0, tzinfo=datetime.timezone.utc), arr_day=0, dep_time=1583067600, dep_time_offset=-18000, arr_time=1583078400, arr_time_offset=-21600, time_adjusted=True, capacity=100, distance=863.7532821438833), Leg(leg_id=None, carrier='AL2', fltno=202, orig='BOS', orig_timezone='America/New_York', dest='ORD', dest_timezone='America/Chicago', date=datetime.datetime(2020, 3, 1, 0, 0, tzinfo=datetime.timezone.utc), arr_day=0, dep_time=1583089200, dep_time_offset=-18000, arr_time=1583100000, arr_time_offset=-21600, time_adjusted=True, capacity=100, distance=863.7532821438833), Leg(leg_id=None, carrier='AL1', fltno=111, orig='ORD', orig_timezone='America/Chicago', dest='LAX', dest_timezone='America/Los_Angeles', date=datetime.datetime(2020, 3, 1, 0, 0, tzinfo=datetime.timezone.utc), arr_day=0, dep_time=1583082000, dep_time_offset=-21600, arr_time=1583096400, arr_time_offset=-28800, time_adjusted=True, capacity=120, distance=1739.79933695373), Leg(leg_id=None, carrier='AL1', fltno=112, orig='ORD', orig_timezone='America/Chicago', dest='LAX', dest_timezone='America/Los_Angeles', date=datetime.datetime(2020, 3, 1, 0, 0, tzinfo=datetime.timezone.utc), arr_day=0, dep_time=1583103600, dep_time_offset=-21600, arr_time=1583118000, arr_time_offset=-28800, time_adjusted=True, capacity=120, distance=1739.79933695373), Leg(leg_id=None, carrier='AL2', fltno=211, orig='ORD', orig_timezone='America/Chicago', dest='LAX', dest_timezone='America/Los_Angeles', date=datetime.datetime(2020, 3, 1, 0, 0, tzinfo=datetime.timezone.utc), arr_day=0, dep_time=1583082000, dep_time_offset=-21600, arr_time=1583096400, arr_time_offset=-28800, time_adjusted=True, capacity=120, distance=1739.79933695373), Leg(leg_id=None, carrier='AL2', fltno=212, orig='ORD', orig_timezone='America/Chicago', dest='LAX', dest_timezone='America/Los_Angeles', date=datetime.datetime(2020, 3, 1, 0, 0, tzinfo=datetime.timezone.utc), arr_day=0, dep_time=1583103600, dep_time_offset=-21600, arr_time=1583118000, arr_time_offset=-28800, time_adjusted=True, capacity=120, distance=1739.79933695373)]
We can see here a list of legs, and each leg has all the attributes needed to define it in the simulation: origin, destination, departure and arrival times, capacity, and more. We can manipulate these attributes if we like. Let's make the capacity on that first leg a little larger.
cfg.legs[0].capacity = 180
We can do the same and peek in on the network fares.
cfg.fares
[Fare(carrier='AL1', orig='BOS', dest='ORD', booking_class='Y0', price=400.0, advance_purchase=0, restrictions=[], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL1', orig='BOS', dest='ORD', booking_class='Y1', price=300.0, advance_purchase=0, restrictions=['R2'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL1', orig='BOS', dest='ORD', booking_class='Y2', price=200.0, advance_purchase=3, restrictions=['R1'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL1', orig='BOS', dest='ORD', booking_class='Y3', price=150.0, advance_purchase=7, restrictions=['R1', 'R2'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL1', orig='BOS', dest='ORD', booking_class='Y4', price=125.0, advance_purchase=14, restrictions=['R1', 'R3'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL1', orig='BOS', dest='ORD', booking_class='Y5', price=100.0, advance_purchase=21, restrictions=['R1', 'R2', 'R3'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL1', orig='ORD', dest='LAX', booking_class='Y0', price=500.0, advance_purchase=0, restrictions=[], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL1', orig='ORD', dest='LAX', booking_class='Y1', price=400.0, advance_purchase=0, restrictions=['R2'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL1', orig='ORD', dest='LAX', booking_class='Y2', price=300.0, advance_purchase=3, restrictions=['R1'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL1', orig='ORD', dest='LAX', booking_class='Y3', price=225.0, advance_purchase=7, restrictions=['R1', 'R2'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL1', orig='ORD', dest='LAX', booking_class='Y4', price=175.0, advance_purchase=14, restrictions=['R1', 'R3'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL1', orig='ORD', dest='LAX', booking_class='Y5', price=150.0, advance_purchase=21, restrictions=['R1', 'R2', 'R3'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL1', orig='BOS', dest='LAX', booking_class='Y0', price=750.0, advance_purchase=0, restrictions=[], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL1', orig='BOS', dest='LAX', booking_class='Y1', price=625.0, advance_purchase=0, restrictions=['R2'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL1', orig='BOS', dest='LAX', booking_class='Y2', price=450.0, advance_purchase=3, restrictions=['R1'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL1', orig='BOS', dest='LAX', booking_class='Y3', price=325.0, advance_purchase=7, restrictions=['R1', 'R2'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL1', orig='BOS', dest='LAX', booking_class='Y4', price=250.0, advance_purchase=14, restrictions=['R1', 'R3'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL1', orig='BOS', dest='LAX', booking_class='Y5', price=200.0, advance_purchase=21, restrictions=['R1', 'R2', 'R3'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL2', orig='BOS', dest='ORD', booking_class='Y0', price=400.0, advance_purchase=0, restrictions=[], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL2', orig='BOS', dest='ORD', booking_class='Y1', price=300.0, advance_purchase=0, restrictions=['R2'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL2', orig='BOS', dest='ORD', booking_class='Y2', price=200.0, advance_purchase=3, restrictions=['R1'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL2', orig='BOS', dest='ORD', booking_class='Y3', price=150.0, advance_purchase=7, restrictions=['R1', 'R2'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL2', orig='BOS', dest='ORD', booking_class='Y4', price=125.0, advance_purchase=14, restrictions=['R1', 'R3'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL2', orig='BOS', dest='ORD', booking_class='Y5', price=100.0, advance_purchase=21, restrictions=['R1', 'R2', 'R3'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL2', orig='ORD', dest='LAX', booking_class='Y0', price=500.0, advance_purchase=0, restrictions=[], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL2', orig='ORD', dest='LAX', booking_class='Y1', price=400.0, advance_purchase=0, restrictions=['R2'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL2', orig='ORD', dest='LAX', booking_class='Y2', price=300.0, advance_purchase=3, restrictions=['R1'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL2', orig='ORD', dest='LAX', booking_class='Y3', price=225.0, advance_purchase=7, restrictions=['R1', 'R2'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL2', orig='ORD', dest='LAX', booking_class='Y4', price=175.0, advance_purchase=14, restrictions=['R1', 'R3'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL2', orig='ORD', dest='LAX', booking_class='Y5', price=150.0, advance_purchase=21, restrictions=['R1', 'R2', 'R3'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL2', orig='BOS', dest='LAX', booking_class='Y0', price=750.0, advance_purchase=0, restrictions=[], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL2', orig='BOS', dest='LAX', booking_class='Y1', price=625.0, advance_purchase=0, restrictions=['R2'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL2', orig='BOS', dest='LAX', booking_class='Y2', price=450.0, advance_purchase=3, restrictions=['R1'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL2', orig='BOS', dest='LAX', booking_class='Y3', price=325.0, advance_purchase=7, restrictions=['R1', 'R2'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL2', orig='BOS', dest='LAX', booking_class='Y4', price=250.0, advance_purchase=14, restrictions=['R1', 'R3'], category=None, cabin='Y', min_stay=0, saturday_night_required=False), Fare(carrier='AL2', orig='BOS', dest='LAX', booking_class='Y5', price=200.0, advance_purchase=21, restrictions=['R1', 'R2', 'R3'], category=None, cabin='Y', min_stay=0, saturday_night_required=False)]
There are a lot of fares for our tiny little network. Perhaps we don't want to edit them one at a time. We can do a little Python programming to modify fares all at once according to some logic. We put a bigger plane on one of AL1's Boston to Chicago legs, so let's lower their fares in that market a smidge to help fill that plane.
for f in cfg.fares:
if f.carrier == "AL1" and f.orig == "BOS" and f.dest == "ORD":
f.price -= 5.0
Not all our changes need to be about the network; we can also manipulate the settings for the simulation itself. Our modified network is just a small experiment, we we don't need to sit around waiting for a statistically useful number of samples to run. Let's cut way back so our simulation runs faster.
cfg.simulation_controls.num_trials = 2
cfg.simulation_controls.num_samples = 200
Now that we've modified our cfg all we want, we can use it to
initialize a simulation to run.
sim = pax.Simulation(cfg)
summary = sim.run()
Task Completed after 1.89 seconds
Having run the simulation, we can take a quick peek at the results.
summary.fig_carrier_revenues()
summary.fig_carrier_rasm()
summary.fig_fare_class_mix()