store resource of SimPy module (Python) not emptied

30 Views Asked by At

I created a simple simulation model of an operation that produces items, stores them, and arranges for delivery of these items at defined hours of the day. I noted that the stores do not get completely emptied at those times, however, and I cannot explain why. Please see minimum reproducible example of code below.

import simpy
import numpy
import pandas
import random
import statistics
import pdb

def itemProducer(env):
    itemCounter = 1
    while True:
        yield env.timeout(numpy.random.exponential(1))
        yield store.put(f'{itemCounter}')

def itemCollector(env, pickupTimes):
    while True:
        yield env.timeout(next(pickupTimes)\
                          - env.now)
        i = len(pickupData)
        pickupData.loc[i,
                       'timeBeforePickup'] = env.now
        pickupData.loc[i,
                       'itemsInStoreBefore'] = \
                       len(store.items)
        for item in store.items:
            yield store.get()
        pickupData.loc[i,
                       'timeAfterPickup'] = env.now
        pickupData.loc[i,
                       'itemsInStoreAfter'] = len(store.items)

#generating endless stream of pickup times:
collectionTimesPerDay = [9, 12, 15, 17]
def endlessTimesGenerator(collectionTimesPerDay):
    t = 0
    while True:
        for i in collectionTimesPerDay:
            yield (t + i)
        t += 24

#for data collection:
pickupData = pandas.DataFrame(columns = ['timeBeforePickup',
                                         'itemsInStoreBefore',
                                         'timeAfterPickup',
                                         'itemsInStoreAfter'])

#defining simulation environment, store etc.:
env = simpy.Environment()
store = simpy.Store(env, capacity = 10000)
pickupTimes = endlessTimesGenerator(collectionTimesPerDay)

env.process(itemProducer(env))

env.process(itemCollector(env, pickupTimes))

env.run(until = 72)

The process itemProducer is supposed to produce items at (average) periods of 1 time-unit (say, hours) and add them to a store for later collection. These periods are exponentially distributed, i.e. not exactly 1 each time. The process itemCollector is meant to empty the stores at given times (see list collectionTimesPerDay).

I added a data-frame pickupData for recording of the number of items in store before and after pick-up. I note that the stores are never cleared completely, a behaviour I would like to achieve, however. For instance, at time 9 (timeBeforePickup column) there are 11 items in store before collection. After collection, there are still 5 left in store. How can I achieve that all of the items are cleared by the itemCollector process at the times defined by pickupTimes?

pickupData
   timeBeforePickup itemsInStoreBefore timeAfterPickup itemsInStoreAfter
0                 9                 11               9                 5
1                12                 10              12                 5
2                15                 10              15                 5
3                17                  8              17                 4
4                33                 22              33                11
5                36                 13              36                 6
6                39                 14              39                 7
7                41                  8              41                 4
8                57                 24              57                12
9                60                 13              60                 6
10               63                  6              63                 3
11               65                  8              65                 4

Any help that leads to the solution of this question would be greatly appreciated.

1

There are 1 best solutions below

0
Michael On BEST ANSWER

The issue is you are changing the list while iterating over it. Iterators hate changes to a list while they iterate over it.

I simply changed

    for item in store.items:

to

while len(store.items) > 0:

Here is the full solution

import simpy
import numpy
import pandas
import random
import statistics
import pdb

def itemProducer(env):
    itemCounter = 1
    while True:
        yield env.timeout(numpy.random.exponential(1))
        yield store.put(f'{itemCounter}')
        itemCounter += 1

def itemCollector(env, pickupTimes):
    while True:
        yield env.timeout(next(pickupTimes)\
                          - env.now)
        i = len(pickupData)
        pickupData.loc[i,
                       'timeBeforePickup'] = env.now
        pickupData.loc[i,
                       'itemsInStoreBefore'] = \
                       len(store.items)
        
        # for item in store.items:
        while len(store.items) > 0:
            pulled = yield store.get()

        pickupData.loc[i,
                       'timeAfterPickup'] = env.now
        pickupData.loc[i,
                       'itemsInStoreAfter'] = len(store.items)

#generating endless stream of pickup times:
collectionTimesPerDay = [9, 12, 15, 17]
def endlessTimesGenerator(collectionTimesPerDay):
    t = 0
    while True:
        for i in collectionTimesPerDay:
            yield (t + i)
        t += 24

#for data collection:
pickupData = pandas.DataFrame(columns = ['timeBeforePickup',
                                         'itemsInStoreBefore',
                                         'timeAfterPickup',
                                         'itemsInStoreAfter'])

#defining simulation environment, store etc.:
env = simpy.Environment()
store = simpy.Store(env, capacity = 10000)
pickupTimes = endlessTimesGenerator(collectionTimesPerDay)

env.process(itemProducer(env))

env.process(itemCollector(env, pickupTimes))

env.run(until = 72)

print(pickupData )