def run(args, shared_blocked, shared_dropped, run_seed):
    np.random.seed(run_seed)  # scipy uses numpy seeds
    args.seed = run_seed
    simulator = Simulator(args)  # init simulator

    # capture stats
    # step-wise statistics no longer required
    # blocked_arr = []
    # dropped_arr = []
    num_inits = num_handover = num_terminate = 0
    warmed_up = False

    for step in range(args.steps):
        if step > args.warmup and not warmed_up:
            simulator.reset()
            warmed_up = True
            # print('Simulator reset')
            # print(f'Total Calls: {simulator.total_calls}')
            # print(f'Blocked Calls: {simulator.blocked_calls}')
            # print(f'Dropped Calls: {simulator.dropped_calls}')
            # print('Leaving simulator reset')

        event = simulator.FEL.dequeue()
        simulator.clock = event.time  # advance clock to event

        if isinstance(event, CallInit):
            simulator.handle_call_init(event)
            num_inits += 1
        elif isinstance(event, CallHandover):
            num_handover += 1
            if args.num_reserve == 0:
                simulator.handle_call_handover_no_res(event)
            else:
                simulator.handle_call_handover_res(event)
        elif isinstance(event, CallTerminate):
            num_terminate += 1
            simulator.handle_call_termination(event)
        else:
            raise TypeError("Wrong event type in FEL")

        # if warmed_up: # only start collecting when warmed up
        #     assert simulator.total_calls != 0
        #     percent_blocked = (simulator.blocked_calls / simulator.total_calls) * 100
        #     percent_dropped = (simulator.dropped_calls / simulator.total_calls) * 100
        #     blocked_arr.append(percent_blocked)
        #     dropped_arr.append(percent_dropped)

    # compute final run statistics
    # for debugging
    # print(f'Total Calls: {simulator.total_calls}')
    # print(f'Blocked Calls: {simulator.blocked_calls}')
    # print(f'Dropped Calls: {simulator.dropped_calls}')

    run_blocked = (simulator.blocked_calls / simulator.total_calls) * 100
    run_dropped = (simulator.dropped_calls / simulator.total_calls) * 100

    # store results in shared list
    shared_blocked.append(run_blocked)
    shared_dropped.append(run_dropped)
def main(args):
    check_path = Path(f'./results/warmups/res_{args.num_reserve}_blocked.npy')
    # capture stats
    blocked_arr = []
    dropped_arr = []
    num_inits = num_handover = num_terminate = 0
    if not check_path.exists():
        # set the base seed
        np.random.seed(args.seed)
        simulator = Simulator(args)  # init simulator

        # for step in tqdm(range(args.steps), leave=False):
        for step in tqdm(range(args.steps)):
            event = simulator.FEL.dequeue()
            simulator.clock = event.time  # advance clock to event
            # clock_times.append(simulator.clock)

            if isinstance(event, CallInit):
                simulator.handle_call_init(event)
                num_inits += 1
            elif isinstance(event, CallHandover):
                num_handover += 1
                if args.num_reserve == 0:
                    simulator.handle_call_handover_no_res(event)
                else:
                    simulator.handle_call_handover_res(event)
            elif isinstance(event, CallTerminate):
                num_terminate += 1
                simulator.handle_call_termination(event)
            else:
                raise TypeError("Wrong event type in FEL")

            blocked_arr.append(
                (simulator.blocked_calls / simulator.total_calls) * 100)
            dropped_arr.append(
                (simulator.dropped_calls / simulator.total_calls) * 100)

        np.save(f'./results/warmups/res_{args.num_reserve}_blocked.npy',
                blocked_arr)
        np.save(f'./results/warmups/res_{args.num_reserve}_dropped.npy',
                dropped_arr)

    else:
        blocked_arr = np.load(
            f'./results/warmups/res_{args.num_reserve}_blocked.npy')
        dropped_arr = np.load(
            f'./results/warmups/res_{args.num_reserve}_dropped.npy')

    fig, ax = plt.subplots()

    ############################ UNUSED ########################
    # plt.plot(clock_times, blocked_percents, label='blocked')
    # plt.plot(clock_times, dropped_percents, label="dropped")
    # plt.xlabel('clock times')
    ############################################################

    ax.plot(blocked_arr, label='blocked')
    ax.plot(dropped_arr, label="dropped")
    ax.vlines(x=args.plot_at,
              ymin=-0.1,
              ymax=args.ymax,
              color='r',
              linestyle='dashed')
    ax.set_xlabel('Number of Events')
    ax.set_ylabel('Percentages')
    plt.legend()
    ax.set_title('Percentages of Dropped and Blocked Calls')

    fig.savefig(f'./images/warmups/res_{args.num_reserve}.png')
def main(args):
    # set the base seed
    np.random.seed(args.seed)
    final_blocked_arr = []
    final_dropped_arr = []
    seeds = list(np.random.randint(1, 20381, size=args.reps))
    print(f'Seeds: {seeds}')

    for rep in tqdm(range(args.reps)):
        np.random.seed(seeds[rep]) # scipy uses numpy seeds
        # print('Simulator initialised')
        args.seed = seeds[rep] # so simulator sets correct internal seed
        simulator = Simulator(args) # init simulator

        # capture stats
        blocked_arr = []
        dropped_arr = []
        num_inits = num_handover = num_terminate = 0
        warmed_up = False

        # for step in tqdm(range(args.steps), leave=False):
        for step in range(args.steps):
            # if step % 10000 == 0:
            #     print(f'Currently in step {step}')
            if step > args.warmup and not warmed_up:
                # print('Simulator reset')
                simulator.reset()
                warmed_up = True

            event = simulator.FEL.dequeue()
            simulator.clock = event.time # advance clock to event
            # clock_times.append(simulator.clock)

            if isinstance(event, CallInit):
                simulator.handle_call_init(event)
                num_inits += 1
            elif isinstance(event, CallHandover):
                num_handover += 1
                if args.num_reserve == 0:
                    simulator.handle_call_handover_no_res(event)
                else:
                    simulator.handle_call_handover_res(event)
            elif isinstance(event, CallTerminate):
                num_terminate += 1
                simulator.handle_call_termination(event)
            else:
                raise TypeError("Wrong event type in FEL")

            if warmed_up: # only start collecting when warmed up
                # print("total calls", simulator.total_calls)
                #! BUG FOUND, not the fault of the pool!!!
                # I had just reset and then entered this section where I attempt to divide by 0
                assert simulator.total_calls != 0
                percent_blocked = (simulator.blocked_calls / simulator.total_calls) * 100
                percent_dropped = (simulator.dropped_calls / simulator.total_calls) * 100
                blocked_arr.append(percent_blocked)
                dropped_arr.append(percent_dropped)

        final_blocked_arr.append(np.mean(blocked_arr))
        final_dropped_arr.append(np.mean(dropped_arr))        

    np.save(f'./results/reps_{args.reps}_blocked.npy', final_blocked_arr)
    np.save(f'./results/reps_{args.reps}_dropped.npy', final_dropped_arr)