(UPDATED) Fast-Time Simulation Series: Release the Nerds

UPDATE: As I got deeper into this process, I had to make some changes to the schedule building code below. I have updated it to the current code (more changes might come) but I’ve kept the old code at the bottom.

Fast-time simulation is a topic that has always teased my interest. I’ve enjoyed building models of some pretty complex systems in Excel, but I’ve pushed that platform to the limit and making the jump up to more sophisticated modelling has always seemed like too big of a leap. It seemed the realm of hardcore coders or professional platforms that don’t have a “play around for free” option.

With ChatGPT on my side, I decided to give it a go this weekend. So, come along with me as I either leap to new heights or fall into an abyss.

ChatGPT’s Got Some Coding Skills

One of the most exciting capabilities of ChatGPT (for plenty of other nerds out there and me) is that it can write computer code. Like much of what it does, the first time you see it punch out some code based on your description of what you want, your jaw drops. 

And then you see the little explanation you get. 

And then, you notice the “copy code” button.

Image of shocked guy by Mikhail Nilov (via Pexels)

For those into programming, it might interest you to know that in addition to writing code in a bunch of programming languages, it can translate between languages. Also, it can add comments to your existing code (as a very informally trained python programmer, I could improve at putting in comments).

For When Time is of the Essence

As much as I love aircraft, I can’t sit watch a year’s worth of aircraft fly in and out of an airport. Especially if I want to predict when problems will arise and how bad they’ll be. Fast-time simulation lets you do that and can let you do it lots and lots of times.

The particular scenario I want to model is a familiar one to many airport managers out there. Is my apron going to fill up during my peak busy day (or hour), and what will the knock-on effects be.

Yes, you could model this (and I have) in Excel but introducing a little real-world randomness is pretty tricky in Excel, especially if you are looking at a minute-by-minute model over a six-month schedule. Furthermore, the complexity increases when you want to introduce a particular type of randomness.

While aircraft don’t always arrive and depart on time, we often have data on the distribution of their on-time performance. We could use those figures to introduce realistic “unpredictability” into our model. However, it is no use modelling a schedule established to ensure apron capacity wasn’t exceeded. That’s not the real world.

I’m sure all of us have experienced one of those horror days where everyone who should be early is late, and everyone who should be late is early. It gets crazy quickly. It doesn’t happen every day, but it does happen. Fast-time simulations let to test out hundreds, if not thousands, of days to see how the airport performs when things go well and when things go wrong.

Setting a Schedule

To set me on this path, the first thing I had to build was a schedule. I initially thought about using a real-life schedule and changing the names. I’m sure I’ve got one lying around here somewhere. But then I had the silly idea that I might want more control. So, let’s build one, I thought.

I should have asked ChatGPT to help me, but I got all cocky, and here I now am, writing a blog post 30 minutes past midnight. I got there in the end, though.

The function I built (see below) uses a broad distribution of flights each hour to construct the hourly schedule. Randomness is introduced into the scheduled arrival and departure times using variables I just made up. I did use ChatGPT to help with some specific aspects of this function and to help me write the comments.

The result is a daily schedule of just under 90 flights. Here is the daily flight distribution:

If you are interested, here is the code (feel free to critique and please note that this was updated after I originally posted this article):

def build_schedule(mean_busy_day_overview):
    # create an empty schedule dataframe
    schedule = pd.DataFrame(columns=['acft_rego', 'sta', 'std'])
    
    # iterate over the hours and flights in the mean_busy_day_overview
    for hour, flights in mean_busy_day_overview.items():
        start_time = 0
        if flights == 0:
          None
        else:  
            # calculate the average time between flights
            average_time_between = int(60 / flights)
            
            # iterate over the number of flights in the hour
            for flight in range(0, flights):
                
                # Randomly generate an aircraft registration
                # create a list of alphabet letters
                letters = list(string.ascii_uppercase)
                # standardised registration initial letter
                rego_code_start = 'FTS'
                # use random.randint() to generate a random 3 digits number
                rego_number = random.randint(10,99)
                # use random.choices() to generate two random letters
                rego_code_end = ''.join(random.choices(letters, k=2))
                # concatenate the flight_code and flight_number
                acft_rego = rego_code_start + str(rego_number) + rego_code_end
                
                # generate a random time variation for the flight 
                # initialization time
                rand_time_var = int(random.normalvariate(0, 5))
                
                # calculate the flight initialization time
                flight_init_min = start_time + average_time_between + rand_time_var
                
                # ensure that the flight initialization time does not exceed 
                # 60 minutes or is less than 0 minutes
                if flight_init_min >= 60:
                    flight_init_min = 60 - 1
                elif flight_init_min < 0:
                    flight_init_min = 0
                
                # ensure that the flight initialization time is in the 
                # format of HH:MM
                if len(str(flight_init_min)) == 1:
                    flight_init_min = str(flight_init_min).zfill(2)
                
                # calculate the scheduled takeoff time (sta)
                sta = str(hour) + ':' + str(flight_init_min)
                
                # standardised turn around time
                sched_turn_time = 40

                # calculate the scheduled takeoff time (std)
                std = datetime.strptime(sta, "%H:%M") + timedelta(minutes=sched_turn_time)
                std = std.strftime("%H:%M")
                
                # create a new row with the calculated values
                new_row = {'acft_rego': acft_rego, 'sta': sta, 'std': std}
                
                # append the new row to the schedule dataframe
                schedule = schedule.append(new_row, ignore_index=True)
                
                # update the start time for the next flight
                start_time = start_time + int(flight_init_min)

    return schedule

Tomorrow, I’m going to build an airport for me to test this schedule out.

Update: I needed to change the original code I posted because it no longer suited the simulation program as a whole. I didn’t need the actual times of arrival and departure or the turn-around time but I’ve kept the code here for future reference. I also removed the OTP discussion as that was not longer relevant.

def build_schedule(mean_busy_day_overview):
    # create an empty schedule dataframe
    schedule = pd.DataFrame(columns=['sta', 'flight_number', 'turn_time', 'std', 'ata', 'atd'])
    
    # iterate over the hours and flights in the mean_busy_day_overview
    for hour, flights in mean_busy_day_overview.items():
        start_time = 0
        if flights == 0:
          None
        else:  
            # calculate the average time between flights
            average_time_between = int(60 / flights)
            
            # iterate over the number of flights in the hour
            for flight in range(0, flights):
                # generate a random time variation for the flight initialization time
                rand_time_var = int(random.normalvariate(0, 3))
                
                # calculate the flight initialization time
                flight_init_min = start_time + average_time_between + rand_time_var
                
                # ensure that the flight initialization time does not exceed 60 minutes or is less than 0 minutes
                if flight_init_min >= 60:
                    flight_init_min = 60 - 1
                elif flight_init_min < 0:
                    flight_init_min = 0
                
                # ensure that the flight initialization time is in the format of HH:MM
                if len(str(flight_init_min)) == 1:
                    flight_init_min = str(flight_init_min).zfill(2)
                
                # calculate the scheduled takeoff time (sta)
                sta = str(hour) + ':' + str(flight_init_min)
                
                # Randomly generate a flight number
                # create a list of alphabet letters
                letters = list(string.ascii_uppercase)
                # use random.choices() to generate two random letters
                flight_code = ''.join(random.choices(letters, k=2))
                # use random.randint() to generate a random 3 digits number
                flight_number = random.randint(100,999)
                # concatenate the flight_code and flight_number
                flight_number = flight_code + str(flight_number)
                
                
                # generate a random turn time variation
                rand_turn_var = random.normalvariate(0, 10)
                turn_time = int(40 + rand_turn_var)
                
                # calculate the scheduled takeoff time (std)
                std = datetime.strptime(sta, "%H:%M") + timedelta(minutes=turn_time)
                std = std.strftime("%H:%M")
                
                # generate random variations for the actual arrival and departure times
                rand_arr_var = int(random.normalvariate(0, 10))
                rand_dep_var = int(random.normalvariate(0, 5))
                
                # calculate the actual arrival time (ata)
                ata = datetime.strptime(sta, "%H:%M") + timedelta(minutes=rand_arr_var)
                ata = ata.strftime("%H:%M")
                
                # calculate the actual departure time (atd)
                atd = datetime.strptime(std, "%H:%M") + timedelta(minutes=rand_dep_var)
                atd = atd.strftime("%H:%M")
                
                # create a new row with the calculated values
                new_row = {'sta': sta, 'flight_number': flight_number, 'turn_time': turn_time, 'std': std, 'ata': ata, 'atd': atd}
                
                # append the new row to the schedule dataframe
                schedule = schedule.append(new_row, ignore_index=True)
                
                # update the start time for the next flight
                start_time = start_time + int(flight_init_min)

    # return the final schedule dataframe
    schedule.to_csv('schedule.csv')
    return schedule
 
Dan Parsons

Dan is an airport operations manager currently working at Queenstown Airport in beautiful New Zealand. His previous roles have included airport and non-process infrastructure operation manager in the mining industry, government inspector with the Civil Aviation Safety Authority and airport trainer. Dan’s special interests include risk management, leadership and process hacks to make running airports easier. 

http://therunwaycentreline.com
Previous
Previous

Fast-Time Simulation: Building an Airport

Next
Next

Friday Funny: ChatGPT-generated Airport-themed Limericks