def _find_queued_pools(self): """ Finds the pools to be created that are still in the queue and determines stock concentration for single design pools. All molecule design pools from the ISO request that are not part of an ISO yet, are used. Cancelled ISOs are ignored. """ used_pools = set() for iso in self.iso_request.isos: if iso.status == ISO_STATUS.CANCELLED: continue if iso.molecule_design_pool_set is None: continue used_pools.update( iso.molecule_design_pool_set.molecule_design_pools) pool_set = self.iso_request.molecule_design_pool_set self._molecule_type = pool_set.molecule_type self._queued_pools = \ pool_set.molecule_design_pools.difference(used_pools) if len(self._queued_pools) < 1: msg = 'There are no unused molecule design pools left!' self.add_error(msg) else: self.__single_design_stock_concentration = \ get_default_stock_concentration(self._molecule_type)
def run(self): """ Creates the ISO request. """ self.reset() self.add_info('Start ISO request creation ...') self.__check_input() if not self.has_errors(): self.__stock_concentration = \ get_default_stock_concentration(self.molecule_type) # The transfer volume from a single design stock tube is # determined by preparation plate volume, stock concentration, # and number of molecule designs per pool. self.__stock_transfer_volume = \ get_stock_transfer_volume( preparation_plate_volume=self.preparation_plate_volume, stock_concentration=self.__stock_concentration, number_designs=self.number_designs) if not self.has_errors(): self.__parse_base_layout() if not self.has_errors(): self.__get_pool_set() if not self.has_errors(): self.__create_worklist_series() if not self.has_errors(): self.__determine_number_of_plates() if not self.has_errors(): self.return_value = self.__create_library() self.add_info('ISO request generation completed.')
def run(self): """ Creates the ISO request. """ self.reset() self.add_info("Start ISO request creation ...") self.__check_input() if not self.has_errors(): self.__stock_concentration = get_default_stock_concentration(self.molecule_type) # The transfer volume from a single design stock tube is # determined by preparation plate volume, stock concentration, # and number of molecule designs per pool. self.__stock_transfer_volume = get_stock_transfer_volume( preparation_plate_volume=self.preparation_plate_volume, stock_concentration=self.__stock_concentration, number_designs=self.number_designs, ) if not self.has_errors(): self.__parse_base_layout() if not self.has_errors(): self.__get_pool_set() if not self.has_errors(): self.__create_worklist_series() if not self.has_errors(): self.__determine_number_of_plates() if not self.has_errors(): self.return_value = self.__create_library() self.add_info("ISO request generation completed.")
def get_pool_transfer_volume(number_designs=DEFAULT_NUMBER_MOLECULE_DESIGNS, stock_concentration=None): """ Returns the volume to transfer from a (single design) stock rack in ul to a library pool rack. :param int number_designs: Number of single molecule designs per library pool. :param str molecule_type_id: ID of the molecule design in the pool. """ if stock_concentration is None: stock_concentration = get_default_stock_concentration(DEFAULT_LIBRARY_MOLECULE_TYPE_ID) dilution_factor = float(stock_concentration) / DEFAULT_POOL_STOCK_RACK_CONCENTRATION total_vol = DEFAULT_POOL_STOCK_RACK_VOLUME / dilution_factor return round(total_vol / number_designs, 1)
def __get_missing_molecule_design_pools(self): # Fetches or creates the molecule design pools for the rows in which # there are only molecule designs given # (invokes :func:`MoleculeDesignPool.create_from_data`). self.add_debug("Find pool IDs for molecule design sets ...") stock_conc = ( get_default_stock_concentration( molecule_type=self.__molecule_type, number_designs=self.__number_molecule_designs ) ) / CONCENTRATION_CONVERSION_FACTOR for md_ids in self.__pools_to_find: mds = set([self.__md_map[md_id] for md_id in md_ids]) mdp_data = dict(molecule_designs=mds, default_stock_concentration=stock_conc) pool = MoleculeDesignPool.create_from_data(mdp_data) self.__pools.add(pool)
def get_stock_transfer_volume( preparation_plate_volume=DEFAULT_PREPARATION_PLATE_VOLUME, stock_concentration=None, number_designs=DEFAULT_NUMBER_MOLECULE_DESIGNS, ): """ Returns the (single) stock transfer volume for the given preparation plate volume, stock concentration and number of molecule designs per pool. """ if stock_concentration is None: stock_concentration = get_default_stock_concentration(DEFAULT_LIBRARY_MOLECULE_TYPE_ID) prep_vol = get_preparation_plate_transfer_volume( source_concentration=stock_concentration, preparation_plate_volume=preparation_plate_volume ) return round(prep_vol / number_designs, 1)
def get_stock_transfer_volume( preparation_plate_volume=DEFAULT_PREPARATION_PLATE_VOLUME, stock_concentration=None, number_designs=DEFAULT_NUMBER_MOLECULE_DESIGNS): """ Returns the (single) stock transfer volume for the given preparation plate volume, stock concentration and number of molecule designs per pool. """ if stock_concentration is None: stock_concentration = \ get_default_stock_concentration(DEFAULT_LIBRARY_MOLECULE_TYPE_ID) prep_vol = get_preparation_plate_transfer_volume( source_concentration=stock_concentration, preparation_plate_volume=preparation_plate_volume) return round(prep_vol / number_designs, 1)
def __get_missing_molecule_design_pools(self): # Fetches or creates the molecule design pools for the rows in which # there are only molecule designs given # (invokes :func:`MoleculeDesignPool.create_from_data`). self.add_debug('Find pool IDs for molecule design sets ...') stock_conc = (get_default_stock_concentration( molecule_type=self.__molecule_type, number_designs=self.__number_molecule_designs)) \ / CONCENTRATION_CONVERSION_FACTOR for md_ids in self.__pools_to_find: mds = set([self.__md_map[md_id] for md_id in md_ids]) mdp_data = dict(molecule_designs=mds, default_stock_concentration=stock_conc) pool = MoleculeDesignPool.create_from_data(mdp_data) self.__pools.add(pool)
def __get_library_metadata(self): """ Determines the ISO request, the library pools for which to pick source tubes, the worklist series and the stock concentration. """ self._iso_request = self.molecule_design_library.iso_request if self._iso_request is None: msg = 'There is no ISO request for this library!' self.add_error(msg) else: self.__worklist_series = self._iso_request.worklist_series self._find_queued_pools() if not self.has_errors(): self.__stock_concentration = \ get_default_stock_concentration(MOLECULE_TYPE)
def get_pool_transfer_volume(number_designs=DEFAULT_NUMBER_MOLECULE_DESIGNS, stock_concentration=None): """ Returns the volume to transfer from a (single design) stock rack in ul to a library pool rack. :param int number_designs: Number of single molecule designs per library pool. :param str molecule_type_id: ID of the molecule design in the pool. """ if stock_concentration is None: stock_concentration = \ get_default_stock_concentration(DEFAULT_LIBRARY_MOLECULE_TYPE_ID) dilution_factor = float(stock_concentration) \ / DEFAULT_POOL_STOCK_RACK_CONCENTRATION total_vol = DEFAULT_POOL_STOCK_RACK_VOLUME / dilution_factor return round(total_vol / number_designs, 1)
def __get_pool_set(self): # Also sets the stock concentration. self.add_debug('Obtain pool set ...') handler = PoolCreationSetParserHandler(self.stream, parent=self) self.__pool_set = handler.get_result() if self.__pool_set is None: msg = 'Unable to parse pool set!' self.add_error(msg) else: self.__number_designs = handler.get_number_designs() mt = handler.get_molecule_type() # In theory we could check the default stock concentrations for # all the single molecule designs. However, for this we would have # to get the corresponding pools first. Since the handler already # made sure that we have equal molecule types and also the number # of designs (1) is always equal it is very unlikely to stumble # across a different concentration. Even so, the optimizer would # not find proper stock samples for these designs. self.__stock_concentration = get_default_stock_concentration(mt)
def __get_pool_set(self): """ Also set the stock concentration. """ self.add_debug('Obtain pool set ...') agg = get_root_aggregate(IMoleculeType) md_type = agg.get_by_id(MOLECULE_TYPE) self.__stock_concentration = get_default_stock_concentration(md_type) handler = LibraryMemberParserHandler( self.stream, number_molecule_designs=NUMBER_MOLECULE_DESIGNS, molecule_type=md_type, parent=self) self.__pool_set = handler.get_result() if self.__pool_set is None: msg = 'Unable to parse library pool set!' self.add_error(msg)
def from_iso_request(cls, iso_request): """ Factory method generating a :class:`VolumeCalculator` for pool :class:`StockSampleIsoRequest` objects. The calculator determines the stock transfer volume for each single molecule design, the buffer volume and checks whether the target volume of the ISO request needs to be adjusted. :param iso_request: Contains all required numbers. :type iso_request: :class:`thelma.entities.iso.StockSampleCreationIsoRequest` """ pool_set = iso_request.molecule_design_pool_set single_design_stock_concentration = \ get_default_stock_concentration(pool_set.molecule_type, number_designs=1) kw = dict( target_volume=iso_request.stock_volume * VOLUME_CONVERSION_FACTOR, target_concentration=iso_request.stock_concentration \ * CONCENTRATION_CONVERSION_FACTOR, number_designs=iso_request.number_designs, stock_concentration=single_design_stock_concentration) return cls(**kw)