Multiple identical Items can be "rented" from a SimPy store element.
The availability of Items is limited to a number lower than the actual demand.
By using yield
statements other processes should wait until their demand can be met.
The simulation should run until all processes have finished and returned their items back to the store.
The following code runs and behaves as expected as long as the number of items is very large so that every demand can be met at any time.
When the number of items is limited to 4 (as in the code below) no scheduling takes place, no elements from the store are "rented". If the processes occur at the same point in time in the simulation both cant "rent" elements from the store
import simpy
import random
from numpy.random import default_rng
rng = default_rng()
# demo arrival array: 3 days with 3 usecases each
arrivals = [3, 3, 3]
# runtime of the simulation
runtime = 200
# store capacity
availability = 4
# demo uscase list
list_of_uscases = [
{
"usecase": "eMotorbike",
"dep_mean": 7,
"dep_std": 1,
"num_Batteries": 4},
{
"usecase": "eCar",
"dep_mean": 17,
"dep_std": 1,
"num_Batteries": 4},
{
"usecase": "eBike",
"dep_mean": 12,
"dep_std": 1,
"num_Batteries": 4,},
]
# function that generates the individual processes = rentals of batteries
def usecase_gen(env):
# for the number of simulated days do:
day = 0
for j in arrivals:
# for the number of usecases per simulated day do:
count = 0
for k in range(j):
# choose a random uscase from the list for all appearances per day
n = random.choice(list_of_uscases)
# add process generator to the process function called "job()"
env.process(job(env, count, day, n["num_Batteries"], n))
count += 1
day += 1
# make sure that a day has 24h
yield env.timeout(24)
# main process function for every uscase appearance = rental of MBs
def job(env, count, day, resources_required, n):
# generate the dummy starting time for a usecase based on the order of appearance
yield env.timeout(count)
# create an empty array to store the used resources
resources_used = []
print('On day {} Uscase {}_{} requires: {} Batteries at time: {}'.format(day, n["usecase"], count, resources_required,
env.now))
# for every resource in resources_required do:
for i in range(resources_required):
# reserve ressources that are passed in the "resources_required" parameter
i = yield resources.get()
# append the used resources to the list of used resources
resources_used.append(i)
print('On day {} Uscase {}_{} rented: {} Batteries at time: {}'.format(day, n["usecase"], count, resources_required,
env.now))
# the batteries are used for usagetime hours
usagetime = 8
yield env.timeout(usagetime) # this yield timeout represents the usage time
# after the usage return the ressources to the store.
for k in resources_used:
yield resources.put(k)
print('-----------------------------------------')
print('UseCase {}_{} that rented on day {} used: {} Batteries for: {} hours'.format(n["usecase"], count, day,
resources_required, runtime))
print('UseCase {}_{} that rented on day {} returned: {} Batteries at time: {}'.format(n["usecase"], count, day,
resources_required, env.now))
print('-----------------------------------------')
# define an environment where the processes live in
env = simpy.Environment()
# define the store where the batteries are stored with "capacity" places
resources = simpy.Store(env, capacity=availability)
# fill the store with elements with an increasing id number
for i in range(resources.capacity):
resources.put({'id': i})
# call the function that generates the individual rental processes
env.process(usecase_gen(env))
# start the simulation
env.run(until=runtime)