Source code for openclsim.model.shift_amount_activity

"""Shift amount activity for the simulation."""


from functools import partial

import openclsim.core as core

from .base_activities import GenericActivity


[docs]class ShiftAmountActivity(GenericActivity): """ ShiftAmountActivity Class forms a specific class for shifting material from an origin to a destination. It deals with a single origin container, destination container and a single processor to move substances from the origin to the destination. It will initiate and suspend processes according to a number of specified conditions. To run an activity after it has been initialized call env.run() on the Simpy environment with which it was initialized. origin: container where the source objects are located. destination: container, where the objects are assigned to processor: resource responsible to implement the transfer. amount: the maximum amount of objects to be transfered. duration: time specified in seconds on how long it takes to transfer the objects. id_: in case of MultiContainers the id_ of the container, where the objects should be removed from or assiged to respectively. start_event: the activity will start as soon as this event is triggered by default will be to start immediately """ def __init__( self, processor, origin, destination, duration=None, amount=None, id_="default", show=False, phase=None, *args, **kwargs, ): super().__init__(*args, **kwargs) """Initialization""" self.origin = origin self.destination = destination self.processor = processor self.amount = amount self.duration = duration self.id_ = id_ self.print = show self.phase = phase def _request_resource_if_available( self, env, amount, activity_id, ): all_available = False while not all_available and amount > 0: # yield until enough content and space available in origin and destination yield env.all_of( events=[self.origin.container.get_available(amount, self.id_)] ) yield from self._request_resource( self.requested_resources, self.processor.resource ) if self.origin.container.get_level(self.id_) < amount: # someone removed / added content while we were requesting the processor, so abort and wait for available # space/content again self._release_resource( self.requested_resources, self.processor.resource, ) continue yield from self._request_resource( self.requested_resources, self.origin.resource ) if self.origin.container.get_level(self.id_) < amount: self._release_resource( self.requested_resources, self.processor.resource, ) self._release_resource( self.requested_resources, self.origin.resource, ) continue all_available = True
[docs] def main_process_function(self, activity_log, env): """Origin and Destination are of type HasContainer.""" assert self.processor.is_at(self.origin) assert self.destination.is_at(self.origin) amount = self.processor.determine_processor_amount( self.origin, self.destination, self.amount, self.id_ ) yield from self._request_resource( self.requested_resources, self.destination.resource ) yield from self._request_resource_if_available( env=env, amount=amount, activity_id=activity_log.id, ) start_time = env.now args_data = { "env": env, "activity_log": activity_log, "activity": self, } yield from self.pre_process(args_data) activity_log.log_entry( t=env.now, activity_id=activity_log.id, activity_state=core.LogState.START, ) start_shift = env.now yield from self._shift_amount( env, amount, activity_id=activity_log.id, ) activity_log.log_entry( t=env.now, activity_id=activity_log.id, activity_state=core.LogState.STOP, ) args_data["start_preprocessing"] = start_time args_data["start_activity"] = start_shift yield from self.post_process(**args_data) # release the unloader, self.destination and mover requests self._release_resource( self.requested_resources, self.destination.resource, self.keep_resources ) if self.origin.resource in self.requested_resources: self._release_resource( self.requested_resources, self.origin.resource, self.keep_resources ) if self.processor.resource in self.requested_resources: self._release_resource( self.requested_resources, self.processor.resource, self.keep_resources )
def _shift_amount( self, env, amount, activity_id, ): self.processor.activity_id = activity_id self.origin.activity_id = activity_id shiftamount_fcn = self._get_shiftamount_fcn(amount) yield from self.processor.process( origin=self.origin, destination=self.destination, id_=self.id_, shiftamount_fcn=shiftamount_fcn, ) def _get_shiftamount_fcn(self, amount): if self.duration is not None: return lambda origin, destination: (self.duration, amount) elif self.phase == "loading": return partial(self.processor.loading, amount=amount) elif self.phase == "unloading": return partial(self.processor.unloading, amount=amount) else: raise RuntimeError( "Both the phase (loading / unloading) and the duration of the shiftamount activity are undefined. At least one is required!" )