I have the following code:
import simpy
import random
import matplotlib.pyplot as plt
import numpy as np

# Parameters
num_edge_nodes = 2
num_cloud_nodes = 2
edge_buffer_size = 10
cloud_buffer_size = 15

# service times
cloud_server_time = 10
A_edge_service_time = 4
A_cloud_service_time = 2
B_edge_sevice_time = 2
B_cloud_service_partialprocess = 4
B_cloud_service_fullprocess = 5
propagation_delay = 1

arrival_rate = 0.8

edge_costs = [1, 2, 3]
cloud_costs = [2, 4, 6]

# Measurements
class Measure:
    def __init__(self, N_arr_a, N_arr_b, drop, total_queuing_delay, edge_cost, cloud_cost):
        self.N_arr_A = N_arr_a
        self.N_arr_B = N_arr_b
        self.drop = drop
        self.total_queuing_delay = total_queuing_delay
        self.edge_cost = edge_cost
        self.cloud_cost = cloud_cost

measurements = Measure(0, 0, 0, 0, 0, 0)

def packet_arrivals(env, micro_data_center, cloud_data_center, data, edge_buffer, cloud_buffer, f_value):
    packet_type_options = ['A', 'B']
    packet_id = 1

    while True:
        packet_type = random.choices(packet_type_options, weights=(1 - f_value, f_value))[0]

        if packet_type == 'A':
            data.N_arr_A += 1
        else:
            data.N_arr_B += 1

        arrival_time = env.now  # Adding current time stamp for calculating delay
        if len(micro_data_center.items) < edge_buffer:
            if packet_type == 'A':
                micro_data_center.put((packet_id, packet_type, A_edge_service_time, arrival_time))
            elif packet_type == 'B':
                micro_data_center.put((packet_id, packet_type, B_edge_sevice_time, arrival_time))
        else:
            if len(cloud_data_center.items) < cloud_buffer:
                if packet_type == 'A':
                    cloud_data_center.put((packet_id, packet_type, A_cloud_service_time + propagation_delay))
                elif packet_type == 'B':
                    cloud_data_center.put((packet_id, packet_type, B_cloud_service_fullprocess + propagation_delay))
            else:
                data.drop += 1

        yield env.timeout(random.expovariate(arrival_rate))
        packet_id += 1

def edge_node(env, micro_data_center, cloud_data_center, node_id, data, edge_cost):
    while True:
        packet_id, packet_type, packet_processing_time, arrival_time = yield micro_data_center.get()

        queuing_delay = env.now - arrival_time
        data.total_queuing_delay += queuing_delay
        data.edge_cost += edge_cost * packet_processing_time
        print(f"Edge Node {node_id} processed packet {packet_id} of type {packet_type} at time {env.now}")

        yield env.timeout(packet_processing_time)
        if packet_type == 'B':
            yield cloud_data_center.put((packet_id, packet_type, B_cloud_service_partialprocess + propagation_delay))

def cloud_node(env, cloud_data_center, node_id, data, cloud_cost):
    while True:
        packet_id, packet_type, packet_processing_time = yield cloud_data_center.get()

        yield env.timeout(packet_processing_time)
        data.cloud_cost += cloud_cost * packet_processing_time
        print(f"Cloud Node {node_id} processed {packet_type} packet {packet_id} (including propagation delay) at time {env.now}")

# Simulation setup
simtime = 100000
packet_loss_rates = []
f_list = np.linspace(0, 1, 20)

# Run the simulation
for f in f_list:
    env = simpy.Environment()
    micro_data_center = simpy.Store(env)
    cloud_data_center = simpy.Store(env)
    measurements = Measure(0, 0, 0, 0, 0, 0)
    env.process(packet_arrivals(env, micro_data_center, cloud_data_center, measurements, edge_buffer_size, cloud_buffer_size, f))

    for node_id in range(num_edge_nodes):
        env.process(edge_node(env, micro_data_center, cloud_data_center, node_id + 1, measurements, edge_costs[node_id % len(edge_costs)]))

    for node_id in range(num_cloud_nodes):
        env.process(cloud_node(env, cloud_data_center, node_id + 1, measurements, cloud_costs[node_id % len(cloud_costs)]))

    env.run(until=simtime)
    packet_loss_rate = measurements.drop / (measurements.N_arr_A + measurements.N_arr_B)
    packet_loss_rates.append(packet_loss_rate)

# Plot packet loss rate over time
plt.plot(f_list, packet_loss_rates)
plt.xlabel('Different f')
plt.ylabel('Packet Loss Rate')
plt.title('Packet Loss Rate over Different f')
plt.show()

tell me how to perform the following task using the above code:
Assume at least 4 Cloud servers. Furthermore, consider at least three different
types of Cloud servers, each featuring a different service speed and a specific
operational cost (that may depend, for example, on the service speed). Test
various combinations of server types and investigate the trade off between the
overall cost, the queuing delays and the packet drop probability