Пример #1
0
 def __build_buffer_transfer_jobs(self, transfer_job_map):
     self.add_debug('Creating buffer transfer jobs.')
     # The buffer worklists are stored with the ISO request.
     ws = self.iso.iso_request.worklist_series
     rs = get_reservoir_spec(RESERVOIR_SPECS_NAMES.QUARTER_MODULAR)
     has_pool_racks = not self.__pool_stock_rack_map is None
     for wl in ws.get_sorted_worklists():
         sec_idx = wl.index % 4
         job_idx = len(transfer_job_map)
         if has_pool_racks and wl.index < 4:
             # Pool stock rack buffer worklist.
             tgt_iso_rack = self.__pool_stock_rack_map.get(sec_idx)
         elif (has_pool_racks and wl.index < 8) \
             or (not has_pool_racks and wl.index < 4):
             # Preparation plate buffer worklist.
             tgt_iso_rack = self.__prep_plate_map.get(sec_idx)
         else: #
             break
         if tgt_iso_rack is None:
             # The last ISO might not have all sectors used.
             continue
         trf_job = SampleDilutionJob(
                     job_idx,
                     wl,
                     tgt_iso_rack.rack,
                     rs,
                     source_rack_barcode=self.BUFFER_RESERVOIR_BARCODE,
                     ignored_positions=
                         self.__empty_stock_rack_positions_map[sec_idx])
         transfer_job_map[job_idx] = (trf_job, wl)
Пример #2
0
 def __build_buffer_transfer_jobs(self, transfer_job_map):
     self.add_debug('Creating buffer transfer jobs.')
     # The buffer worklists are stored with the ISO request.
     ws = self.iso.iso_request.worklist_series
     rs = get_reservoir_spec(RESERVOIR_SPECS_NAMES.QUARTER_MODULAR)
     has_pool_racks = not self.__pool_stock_rack_map is None
     for wl in ws.get_sorted_worklists():
         sec_idx = wl.index % 4
         job_idx = len(transfer_job_map)
         if has_pool_racks and wl.index < 4:
             # Pool stock rack buffer worklist.
             tgt_iso_rack = self.__pool_stock_rack_map.get(sec_idx)
         elif (has_pool_racks and wl.index < 8) \
             or (not has_pool_racks and wl.index < 4):
             # Preparation plate buffer worklist.
             tgt_iso_rack = self.__prep_plate_map.get(sec_idx)
         else:  #
             break
         if tgt_iso_rack is None:
             # The last ISO might not have all sectors used.
             continue
         trf_job = SampleDilutionJob(
             job_idx,
             wl,
             tgt_iso_rack.rack,
             rs,
             source_rack_barcode=self.BUFFER_RESERVOIR_BARCODE,
             ignored_positions=self.
             __empty_stock_rack_positions_map[sec_idx])
         transfer_job_map[job_idx] = (trf_job, wl)
Пример #3
0
    def __init__(self, entity, mode, user=None, **kw):
        """
        Constructor:

        :param entity: The ISO job or ISO to process.
        :type entity: :class:`thelma.entities.job.IsoJob` or
            :class:`thelma.entities.iso.LabIso`.

        :param mode: :attr:`MODE_EXECUTE` or :attr:`MODE_PRINT_WORKLISTS`
        :type mode: str

        :param user: The user who conducts the DB update (required for
            execution mode).
        :type user: :class:`thelma.entities.user.User`
        :default user: *None*
        """
        StockTransferWriterExecutor.__init__(self,
                                             entity=entity,
                                             mode=mode,
                                             user=user,
                                             **kw)

        #: The lab ISO requests the entity belongs to.
        self._iso_request = None
        #: The final layout for each ISO in this entity mapped onto ISOs.
        self.__final_layouts = None
        #: see :class:`LAB_ISO_ORDERS`.
        self._processing_order = None
        #: The expected :class:`ISO_STATUS.
        self._expected_iso_status = None

        #: The involved racks (as list of :class:`IsoRackContainer`
        #: objects) mapped onto rack markers. Final plates are mapped onto the
        #: :attr:`LABELS.ROLE_FINAL` marker.
        self.__rack_containers = None
        #: The final plates (as list of :class:`IsoRackContainer` objects)
        #: mapped onto ISOs.
        self.__final_plates = None
        #: The layout for each plate mapped onto plate label.
        self.__plate_layouts = None
        #: The ignored positions for each plate.
        self.__ignored_positions = None
        #: The stock rack for this entity mapped onto labels.
        self._stock_racks = None
        #: The stock rack layouts mapped onto stock rack barcodes
        #: (for reporting).
        self.__stock_rack_layouts = None

        #: The job indices for the buffer dilutions.
        self.__buffer_dilution_indices = None
        #: The merged stream for the buffer dilutions (printer mode only).
        self.__buffer_stream = None

        #: The source :class:`ReservoirSpecs` for the dilution jobs.
        self.__dilution_rs = get_reservoir_spec(self.DILUTION_RESERVOIR_SPECS)
Пример #4
0
 def __get_reservoir_specs(self, rack_container):
     # Also records an error message if the spec has not been found.
     try:
         rs = get_reservoir_spec(rack_container.specs.lower())
     except ValueError as ve:
         msg = 'Error when trying to fetch reservoir specs for rack "%s": ' \
               '%s' % (rack_container.identifier, ve)
         self.add_error(msg)
         result = None
     else:
         result = rs
     return result
Пример #5
0
 def _create_optimem_job(self, optimem_worklist):
     """
     Helper function creating an optimem dilution job.
     """
     quarter_rs = get_reservoir_spec(RESERVOIR_SPECS_NAMES.QUARTER_MODULAR)
     optimem_job = SampleDilutionJob(index=0,
                    planned_worklist=optimem_worklist,
                    target_rack=self._source_plate,
                    reservoir_specs=quarter_rs,
                    source_rack_barcode=self.OPTIMEM_PLATE_BARCODE,
                    ignored_positions=self._ignored_positions)
     return optimem_job
Пример #6
0
 def _create_reagent_job(self, reagent_worklist):
     """
     Helper function creating an transfection reagent dilution job.
     """
     tube_24_rs = get_reservoir_spec(RESERVOIR_SPECS_NAMES.TUBE_24)
     reagent_job = SampleDilutionJob(index=1,
                    planned_worklist=reagent_worklist,
                    target_rack=self._source_plate,
                    reservoir_specs=tube_24_rs,
                    source_rack_barcode=self.REAGENT_PLATE_BARCODE,
                    ignored_positions=self._ignored_positions)
     return reagent_job
Пример #7
0
    def __init__(self, entity, mode, user=None, **kw):
        """
        Constructor:

        :param entity: The ISO job or ISO to process.
        :type entity: :class:`thelma.entities.job.IsoJob` or
            :class:`thelma.entities.iso.LabIso`.

        :param mode: :attr:`MODE_EXECUTE` or :attr:`MODE_PRINT_WORKLISTS`
        :type mode: str

        :param user: The user who conducts the DB update (required for
            execution mode).
        :type user: :class:`thelma.entities.user.User`
        :default user: *None*
        """
        StockTransferWriterExecutor.__init__(self, entity=entity, mode=mode,
                                             user=user, **kw)

        #: The lab ISO requests the entity belongs to.
        self._iso_request = None
        #: The final layout for each ISO in this entity mapped onto ISOs.
        self.__final_layouts = None
        #: see :class:`LAB_ISO_ORDERS`.
        self._processing_order = None
        #: The expected :class:`ISO_STATUS.
        self._expected_iso_status = None

        #: The involved racks (as list of :class:`IsoRackContainer`
        #: objects) mapped onto rack markers. Final plates are mapped onto the
        #: :attr:`LABELS.ROLE_FINAL` marker.
        self.__rack_containers = None
        #: The final plates (as list of :class:`IsoRackContainer` objects)
        #: mapped onto ISOs.
        self.__final_plates = None
        #: The layout for each plate mapped onto plate label.
        self.__plate_layouts = None
        #: The ignored positions for each plate.
        self.__ignored_positions = None
        #: The stock rack for this entity mapped onto labels.
        self._stock_racks = None
        #: The stock rack layouts mapped onto stock rack barcodes
        #: (for reporting).
        self.__stock_rack_layouts = None

        #: The job indices for the buffer dilutions.
        self.__buffer_dilution_indices = None
        #: The merged stream for the buffer dilutions (printer mode only).
        self.__buffer_stream = None

        #: The source :class:`ReservoirSpecs` for the dilution jobs.
        self.__dilution_rs = get_reservoir_spec(self.DILUTION_RESERVOIR_SPECS)
Пример #8
0
 def _create_optimem_job(self, optimem_worklist):
     """
     Helper function creating an optimem dilution job.
     """
     quarter_rs = get_reservoir_spec(RESERVOIR_SPECS_NAMES.QUARTER_MODULAR)
     optimem_job = SampleDilutionJob(
         index=0,
         planned_worklist=optimem_worklist,
         target_rack=self._source_plate,
         reservoir_specs=quarter_rs,
         source_rack_barcode=self.OPTIMEM_PLATE_BARCODE,
         ignored_positions=self._ignored_positions)
     return optimem_job
Пример #9
0
 def _create_reagent_job(self, reagent_worklist):
     """
     Helper function creating an transfection reagent dilution job.
     """
     tube_24_rs = get_reservoir_spec(RESERVOIR_SPECS_NAMES.TUBE_24)
     reagent_job = SampleDilutionJob(
         index=1,
         planned_worklist=reagent_worklist,
         target_rack=self._source_plate,
         reservoir_specs=tube_24_rs,
         source_rack_barcode=self.REAGENT_PLATE_BARCODE,
         ignored_positions=self._ignored_positions)
     return reagent_job
Пример #10
0
 def __create_buffer_transfer_job(self):
     # Creates the transfer job for the buffer worklist.
     self.add_debug('Create buffer transfer jobs ...')
     worklist_series = self.entity.iso_request.worklist_series
     buffer_worklist = worklist_series.get_worklist_for_index(
         StockSampleCreationWorklistGenerator.BUFFER_WORKLIST_INDEX)
     rs = get_reservoir_spec(RESERVOIR_SPECS_NAMES.FALCON_MANUAL)
     job_index = len(self._transfer_jobs)
     cdj = SampleDilutionJob(
         index=job_index,
         planned_worklist=buffer_worklist,
         target_rack=self.__pool_stock_rack.rack,
         reservoir_specs=rs,
         source_rack_barcode=self.BUFFER_RESERVOIR_BARCODE,
         ignored_positions=self.__ignore_positions)
     self._transfer_jobs[job_index] = cdj
Пример #11
0
def get_dynamic_dead_volume(target_well_number,
                            reservoir_specs=RESERVOIR_SPECS_NAMES.STANDARD_96):
    """
    Calculate a dynamic dead volume (for pipetting specs that require dynamic
    dead volumes, such as Biomek).

    :param target_well_number: The number of target wells for the given
        source well.
    :type target_well_number: :class:` int`

    :param reservoir_specs: The reservoir specs you are assuming.
    :type reservoir_specs: a :class:`RESERVOIR_SPECS_NAMES` element or
        a :class:`thelma.entities.liquidtransfer.ReservoirSpecs` object
    :default reservoir_specs: RESERVOIR_SPECS_NAMES.STANDARD_96

    :Note: At the moment corrections are only applied to plates.

    :raises TypeError: if resrevoir_specs is not a string or ReservoirSpecs
    :return: The adjusted dead volume in ul.
    """

    if isinstance(reservoir_specs, ReservoirSpecs):
        rs = reservoir_specs
    elif isinstance(reservoir_specs, basestring):
        rs = get_reservoir_spec(reservoir_specs)
    else:
        msg = 'Unsupported type for reservoir specs: %s. Expectes string ' \
              'or ReservoirSpecs object.' % (reservoir_specs.__class__.__name__)
        raise TypeError(msg)

    # pylint: disable=E1103
    min_dead_volume_ul = rs.min_dead_volume * VOLUME_CONVERSION_FACTOR
    max_dead_volume_ul = rs.max_dead_volume * VOLUME_CONVERSION_FACTOR
    # pylint: enable=E1103

    if min_dead_volume_ul == max_dead_volume_ul:
        return min_dead_volume_ul

    if target_well_number <= LIMIT_TARGET_WELLS:
        return min_dead_volume_ul

    exceeding_well_count = target_well_number - LIMIT_TARGET_WELLS
    additional_volume = exceeding_well_count * DEAD_VOLUME_COEFFICIENT
    adjusted_dead_volume = min_dead_volume_ul + additional_volume
    if adjusted_dead_volume > max_dead_volume_ul:
        adjusted_dead_volume = max_dead_volume_ul
    return adjusted_dead_volume
Пример #12
0
def get_dynamic_dead_volume(target_well_number,
                            reservoir_specs=RESERVOIR_SPECS_NAMES.STANDARD_96):
    """
    Calculate a dynamic dead volume (for pipetting specs that require dynamic
    dead volumes, such as Biomek).

    :param target_well_number: The number of target wells for the given
        source well.
    :type target_well_number: :class:` int`

    :param reservoir_specs: The reservoir specs you are assuming.
    :type reservoir_specs: a :class:`RESERVOIR_SPECS_NAMES` element or
        a :class:`thelma.entities.liquidtransfer.ReservoirSpecs` object
    :default reservoir_specs: RESERVOIR_SPECS_NAMES.STANDARD_96

    :Note: At the moment corrections are only applied to plates.

    :raises TypeError: if resrevoir_specs is not a string or ReservoirSpecs
    :return: The adjusted dead volume in ul.
    """

    if isinstance(reservoir_specs, ReservoirSpecs):
        rs = reservoir_specs
    elif isinstance(reservoir_specs, basestring):
        rs = get_reservoir_spec(reservoir_specs)
    else:
        msg = 'Unsupported type for reservoir specs: %s. Expectes string ' \
              'or ReservoirSpecs object.' % (reservoir_specs.__class__.__name__)
        raise TypeError(msg)

    # pylint: disable=E1103
    min_dead_volume_ul = rs.min_dead_volume * VOLUME_CONVERSION_FACTOR
    max_dead_volume_ul = rs.max_dead_volume * VOLUME_CONVERSION_FACTOR
    # pylint: enable=E1103

    if min_dead_volume_ul == max_dead_volume_ul:
        return min_dead_volume_ul

    if target_well_number <= LIMIT_TARGET_WELLS:
        return min_dead_volume_ul

    exceeding_well_count = target_well_number - LIMIT_TARGET_WELLS
    additional_volume = exceeding_well_count * DEAD_VOLUME_COEFFICIENT
    adjusted_dead_volume = min_dead_volume_ul + additional_volume
    if adjusted_dead_volume > max_dead_volume_ul:
        adjusted_dead_volume = max_dead_volume_ul
    return adjusted_dead_volume
Пример #13
0
 def _add_cell_suspension_job(self, cell_worklist, job_index, plate,
                              cell_ignored_positions):
     """
     Helper function registering a container dilution job for the given
     worklist, plate and job index. In addition, in increments the
     job index.
     """
     falcon_reservoir = get_reservoir_spec(
                                         RESERVOIR_SPECS_NAMES.FALCON_MANUAL)
     cell_job = SampleDilutionJob(index=job_index,
                 planned_worklist=cell_worklist,
                 target_rack=plate,
                 reservoir_specs=falcon_reservoir,
                 ignored_positions=cell_ignored_positions)
     self._transfer_jobs[job_index] = cell_job
     job_index += 1
     return job_index
Пример #14
0
 def _add_cell_suspension_job(self, cell_worklist, job_index, plate,
                              cell_ignored_positions):
     """
     Helper function registering a container dilution job for the given
     worklist, plate and job index. In addition, in increments the
     job index.
     """
     falcon_reservoir = get_reservoir_spec(
         RESERVOIR_SPECS_NAMES.FALCON_MANUAL)
     cell_job = SampleDilutionJob(index=job_index,
                                  planned_worklist=cell_worklist,
                                  target_rack=plate,
                                  reservoir_specs=falcon_reservoir,
                                  ignored_positions=cell_ignored_positions)
     self._transfer_jobs[job_index] = cell_job
     job_index += 1
     return job_index
Пример #15
0
 def __create_buffer_transfer_job(self):
     # Creates the transfer job for the buffer worklist.
     self.add_debug("Create buffer transfer jobs ...")
     worklist_series = self.entity.iso_request.worklist_series
     buffer_worklist = worklist_series.get_worklist_for_index(
         StockSampleCreationWorklistGenerator.BUFFER_WORKLIST_INDEX
     )
     rs = get_reservoir_spec(RESERVOIR_SPECS_NAMES.FALCON_MANUAL)
     job_index = len(self._transfer_jobs)
     cdj = SampleDilutionJob(
         index=job_index,
         planned_worklist=buffer_worklist,
         target_rack=self.__pool_stock_rack.rack,
         reservoir_specs=rs,
         source_rack_barcode=self.BUFFER_RESERVOIR_BARCODE,
         ignored_positions=self.__ignore_positions,
     )
     self._transfer_jobs[job_index] = cdj
Пример #16
0
    def __init__(self, reagent_stream_content, parent=None):
        """
        Constructor.

        :param str reagent_stream_content: The content of the reagent dilution
            worklist stream.
        """
        CsvWriter.__init__(self, parent=parent)
        #: The content of the reagent dilution worklist stream.
        self.reagent_stream_content = reagent_stream_content
        #: The relevant data of the worklist (key: line index, values:
        #: tuple (source pos, dilution volume, diluent info) .
        self.__worklist_data = None
        #: The estimated dead volume in ul.
        self.__dead_volume = get_reservoir_spec(RESERVOIR_SPECS_NAMES.TUBE_24).\
                             max_dead_volume * VOLUME_CONVERSION_FACTOR
        #: Intermediate storage for the column values.
        self.__position_values = None
        self.__name_values = None
        self.__final_dil_factor_values = None
        self.__ini_dil_factor_values = None
        self.__total_volume_values = None
        self.__reagent_volume_values = None
        self.__diluent_volume_values = None
Пример #17
0
    def __init__(self, reagent_stream_content, parent=None):
        """
        Constructor.

        :param str reagent_stream_content: The content of the reagent dilution
            worklist stream.
        """
        CsvWriter.__init__(self, parent=parent)
        #: The content of the reagent dilution worklist stream.
        self.reagent_stream_content = reagent_stream_content
        #: The relevant data of the worklist (key: line index, values:
        #: tuple (source pos, dilution volume, diluent info) .
        self.__worklist_data = None
        #: The estimated dead volume in ul.
        self.__dead_volume = get_reservoir_spec(RESERVOIR_SPECS_NAMES.TUBE_24).\
                             max_dead_volume * VOLUME_CONVERSION_FACTOR
        #: Intermediate storage for the column values.
        self.__position_values = None
        self.__name_values = None
        self.__final_dil_factor_values = None
        self.__ini_dil_factor_values = None
        self.__total_volume_values = None
        self.__reagent_volume_values = None
        self.__diluent_volume_values = None