如何模拟允许等到下一个过程解决?

How to simulation allow to wait until the next process is resolved?

<这是一个简短的场景> 患者到达 ED(急诊室)。当患者到达急诊室时,他们首先会接受护士的分类。分流后,患者将被分配到急诊床,但如果患者没有干净的床,他们必须等到脏床。 (脏床出现在病人出院或去IU(Inpatient Unit)。)这里等待的意义有两种情况,第一种是当病人到达时,如果只有一张脏床(没有清理),系统应下达清洁命令。 第二个是,如果没有脏床,这意味着现在正在清洁脏床或等到患者出院或去 IU(发生脏床事件)。当分配 ED 床时,患者是由医生治疗。医生检查后,患者要么去 ​​IU,要么出院。当患者去IU时,如果IU内有干净的床位,则立即归还ED床位,如果没有,则患者必须继续在ED床位等待。 如果患者出院,急诊床将被归还,但不会立即进行清洁。(在清洁命令发出之前将其弄脏)脏的急诊床会根据要求清洁,然后分配给新来的患者。不管怎样,我现在很难实现我的程序的部分是分配 ED 床的部分没有按照我的预期实现。

所以,我的主要问题是

  1. 患者应该清洁急诊床。
  2. 如果没有干净的床,病人等到有干净的床可用。 (等待的患者会继续等待,但其他患者的过程会继续。)
  3. 当病人离开急诊室时,病人使用的床仍然很脏,但如果有新病人的清洁要求,应该清洁脏床。

我添加了 'Bed_Mgmt' class 来解决这个问题,但我做不到。请给我一些指导。

import simpy
import random

class Pre_Define:
    warmup_period = 1440
    sim_duration = 14400
    number_of_runs = 3
    n_edbed = 77

class Patients:
    def __init__(self, p_id):
        self.id = p_id
        self.bed_name = ""
        self.admission_decision = ""
    def admin_decision(self):
        admin_decision_prob = random.uniform(0, 1)
        if admin_decision_prob <= 0.7:
            self.admission_decision = "DIS"
        else:
            self.admission_decision = "IU"

class Bed_Mgmt:
    def __init__(self, env):
        self.env = env
        
    def check_q(self, Pt_id, pt_ed_q, bed_clean, bed_dirty, bed_cleaner): #, pt_ed_q, pt_ed_q, dirty_bed_q
        if pt_ed_q != [] and bed_clean != []:
            Patients.bed_name = bed_clean.get()
            Pt_id = pt_ed_q.get()
        elif pt_ed_q != [] and bed_clean == [] and bed_dirty != []:
            get_dirty_bed_name = bed_dirty.get() 
            with bed_cleaner.request() as req:
                yield req
                yield self.env.timeout(50)
                Patients.bed_name = get_dirty_bed_name
        else: # self.pt_ed_q != [] and self.clean_bed_q == [] and self.dirty_bed_q == []:
            pass  # generate patient

class Model:
    def __init__(self, run_number):
        self.env = simpy.Environment()
        self.pt_ed_q = simpy.Store(self.env )
        self.pt_counter = 0
        self.tg = simpy.Resource(self.env, capacity = 4)
        self.physician = simpy.Resource(self.env, capacity = 4)
        self.bed_clean = simpy.Store(self.env, capacity = Pre_Define.n_edbed)
        self.bed_dirty = simpy.Store(self.env, capacity = Pre_Define.n_edbed)
        self.IU_bed = simpy.Resource(self.env, capacity = 50)   
        self.bed_cleaner = simpy.Resource(self.env, capacity = 2)
        self.run_number = run_number
        
    def generate_beds(self):
        for i in range(Pre_Define.n_edbed):
            yield self.env.timeout(0)
            yield self.bed_clean.put(f'bed{i}')
        print(self.bed_clean.items)
       
    def generate_pt_arrivals(self):
        while True:
            self.pt_counter += 1
            pt = Patients(self.pt_counter)
            yield self.env.timeout(1/7)
            self.env.process(self.ED_Process(pt))
            #self.pt_ed_q.put(pt.id)

    def Process(self, Patients, Bed_Mgmt):
        with self.tg.request() as req:
            yield req
            triage_service_time = random.expovariate(1.0/18)
            yield self.env.timeout(triage_service_time)
        
        yield self.pt_ed_q.put(Patients.id)
        pt_id = yield self.pt_ed_q.get()
        Bed_Mgmt.check_q(pt_id, self.pt_ed_q, self.bed_clean, self.bed_dirty, self.bed_cleaner)

        with self.physician.request() as req:
            yield req
            yield self.env.timeout(10)
            Patients.admin_decision()
            
        if Patients.admission_decision == "DIS":
            with self.IU_bed.request() as req:
                yield req
                Bed_Mgmt.check_q(pt_id, self.pt_ed_q, self.bed_clean, self.bed_dirty, self.bed_cleaner)
                yield self.env.timeout(600)
                get_dirty_bed_name = Patients.bed_name
                yield self.bed_dirty.put(get_dirty_bed_name)
        else:
            get_dirty_bed_name = Patients.bed_name
            Bed_Mgmt.check_q(pt_id, self.pt_ed_q, self.bed_clean, self.bed_dirty, self.bed_cleaner)
            yield self.bed_dirty.put(get_dirty_bed_name)

    def run(self):
        self.env.process(self.generate_pt_arrivals())
        self.env.process(self.generate_beds())
        self.env.run(until = Pre_Define.warmup_period + Pre_Define.sim_duration)

for run in range(Pre_Define.number_of_runs):
    run_model = Model(run)
    run_model.run()
    print()

所以这清理了一些东西。您将在日志的开头看到患者在分诊结束后立即得到一张床,因为队列中有床位。在日志的末尾,您会看到患者在清洁工完成清洁床之前无法得到床位,这表明清洁床队列是空的。 simpy.Store 的优点之一是它为您管理请求,因此您无需检查队列是否为空。 https://realpython.com/ 也是学习 python.

的好网站
import simpy
import random

class Pre_Define:
    warmup_period = 1440
    sim_duration = 14400
    number_of_runs = 1 #3
    n_edbed = 77

class Patients:
    def __init__(self, p_id):
        self.id = p_id
        self.bed_name = ""
        self.admission_decision = ""

    def admin_decision(self):
        admin_decision_prob = random.uniform(0, 1)
        if admin_decision_prob <= 0.7:
            self.admission_decision = "DIS"
        else:
            self.dmission_decision = "IU"

        return self.admission_decision

    

# class Bed_Mgmt:
#     def __init__(self, env):
#         self.env = env
        
#     def check_q(self, Pt_id, pt_ed_q, bed_clean, bed_dirty, bed_cleaner): #, pt_ed_q, pt_ed_q, dirty_bed_q
#         if pt_ed_q != [] and bed_clean != []:
#             Patients.bed_name = bed_clean.get()
#             Pt_id = pt_ed_q.get()
#         elif pt_ed_q != [] and bed_clean == [] and bed_dirty != []:
#             get_dirty_bed_name = bed_dirty.get() 
#             with bed_cleaner.request() as req:
#                 yield req
#                 yield self.env.timeout(50)
#                 Patients.bed_name = get_dirty_bed_name
#         else: # self.pt_ed_q != [] and self.clean_bed_q == [] and self.dirty_bed_q == []:
#             pass  # generate patient

class Model:
    def __init__(self, run_number):
        self.env = simpy.Environment()
        self.pt_ed_q = simpy.Store(self.env )
        self.pt_counter = 0
        self.tg = simpy.Resource(self.env, capacity = 4)
        self.physician = simpy.Resource(self.env, capacity = 4)
        self.bed_clean = simpy.Store(self.env)
        self.bed_dirty = simpy.Store(self.env)
        self.IU_bed = simpy.Resource(self.env, capacity = 50)   
        # self.bed_cleaner = simpy.Resource(self.env, capacity = 2)
        self.run_number = run_number
        
    def generate_beds(self):
        for i in range(Pre_Define.n_edbed):
            yield self.env.timeout(0)
            yield self.bed_clean.put(f'bed{i}')
        print(self.bed_clean.items)
       
    def generate_pt_arrivals(self):
        while True:
            self.pt_counter += 1
            pt = Patients(self.pt_counter)
            #yield self.env.timeout(1/7)
            yield self.env.timeout(5)
            self.env.process(self.ed_process(pt))
            #self.pt_ed_q.put(pt.id)

    def clean_beds_process(self, cleaner_id):
        """
            contious process for cleaning beds
            feeds off of the dirty bed queue
            if the queue is empty, will wait 
            until a bed is added to the queue.
            Clean beds are returned to the clean bed queue

            This process is the cleaner.  
            It one instance of th process is started for each cleaner
        """

        while True:

            # wait untile there is a bed in the dirty bead queue
            bed = yield self.bed_dirty.get()

            print(f'{self.env.now:.2f}  cleaner {cleaner_id} has started to clean bed {bed}')

            # clean bed
            yield self.env.timeout(50)

            print(f'{self.env.now:.2f}  cleaner {cleaner_id} has finish cleaning bed {bed}')

            # put bed in clean bed queue, loop to wait for next dirty bead
            yield self.bed_clean.put(bed)


    def ed_process(self, pt):
        # process for treating a patient

        print(f'{self.env.now:.2f}  patient  {pt.id} has arrived')
        with self.tg.request() as req:
            yield req
            triage_service_time = random.expovariate(1.0/18)
            yield self.env.timeout(triage_service_time)
        
        print(f'{self.env.now:.2f}  patient  {pt.id} has been triaged')
        
        # yield self.pt_ed_q.put(Patients.id)
        # pt_id = yield self.pt_ed_q.get()
        # Bed_Mgmt.check_q(pt_id, self.pt_ed_q, self.bed_clean, self.bed_dirty, self.bed_cleaner)

        bed = yield self.bed_clean.get()
        pt.bed_name = bed
        print(f'{self.env.now:.2f}  patient {pt.id} has a clean EU bed {bed}')

        with self.physician.request() as req:
            yield req
            yield self.env.timeout(10)
            pt.admin_decision()

            print(f'{self.env.now:.2f}  patient {pt.id} has admission descesion of  {pt.admission_decision}')
            
        if pt.admission_decision == "DIS":
            with self.IU_bed.request() as req:
                yield req
                # Bed_Mgmt.check_q(pt_id, self.pt_ed_q, self.bed_clean, self.bed_dirty, self.bed_cleaner)
                
                # have IU bed can give up EU bed
                dirty_bed_name = pt.bed_name
                yield self.bed_dirty.put(dirty_bed_name)

                print(f'{self.env.now:.2f}  patient {pt.id} moved to IU giving up bed {dirty_bed_name}')

                # time until IU bed becomes becone available 
                yield self.env.timeout(600)
                print(f'{self.env.now:.2f}  IU bed is available')
        else:
            # patient leaves EU
            dirty_bed_name = pt.bed_name
            #Bed_Mgmt.check_q(pt_id, self.pt_ed_q, self.bed_clean, self.bed_dirty, self.bed_cleaner)
            yield self.bed_dirty.put(dirty_bed_name)

            print(f'{self.env.now:.2f}  patient {pt.id} left EU giving up bed {dirty_bed_name}')


    def run(self):
        self.env.process(self.generate_pt_arrivals())
        self.env.process(self.generate_beds())

        # creating and starting two cleaners
        for i in range(2):
            self.env.process(self.clean_beds_process(i+1))
        
        #self.env.run(until = Pre_Define.warmup_period + Pre_Define.sim_duration)
        self.env.run(until = 650)

for run in range(Pre_Define.number_of_runs):
    run_model = Model(run)
    run_model.run()
    print()